闲扯 『 document.write 』 男娘i 2021-07-05 02:44 439阅读 0赞 初春的晚上,闲来无事,聊聊 `document.write` 方法。 `document.write` 使用方式非常简单,把 “字符串化”(不好意思,这可能是我自己创造的名词)的 `html` 代码当做参数传入就 `ok` 了,我并不打算讲它的基本用法,可以参考以下链接: > HTML DOM write() 方法 > HTML DOM write() Method > Document.write() > Using document.write `document.write` 经常会被用来加载脚本,比如这样: var url = 'http://ads.com/buyme?rand='+Math.random() document.write('<script src="'+url+'"></scr'+'ipt>') 传统方式: var script = document.createElement('script') script.src = 'http://ads.com/buyme?rand='+Math.random() // now append the script into HEAD, it will fetched and executed document.documentElement.firstChild.appendChild(script) 对比 `dom` 插入的传统方法,的确能少几行代码。这样做还有个好处,它比 `dom` 插入的方式快,因为它是在一个输出流中,所以不用修改 `dom` 结构(`It is very fast, because the browser doesn’t have to modify an existing DOM structure`)。但是,如果这段脚本没有执行完,后续渲染都将挂起! `document.write` 加载脚本也不是没有合适的场景,比如说后续的渲染都要依赖这段脚本,那么这样写就完全没有问题。比如这段代码: <script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.3.min.js"><\/script>')</script> 或者: <script>window.JSON || document.write('<script src="json2.js"><\/script>')</script> 非常的优雅。 还有个应用场景,加载第三方广告,百度联盟的广告就是用该方法输出的。我们假设百度联盟广告如下(另存为 cm.js): document.write("<img src='ad.jpg /'>"); 那么我们在页面任意部分同步加载这段代码,就能显现百度广告,事实上,体验是非常差的,因为是同步渲染,如果这段代码没有执行完,后续是不会执行下去的(UI 挂起)。尝试着将内含 `document.write` 的脚本文件异步执行,写个简单的 demo。 index.htm 文件: <body> Hello <script> var s = document.createElement("script"); s.src = "data.js"; document.body.appendChild(s); </script> </body> data.js 文件: document.write('World'); 页面只显示了 Hello 字样,控制台打印 `notice` 如下(详见 stackoverflow): ![在这里插入图片描述][20201116175021427.png] 按照 `notice` 的提示将 `document.open()` 加入 `data.js` 文件,这时页面就只有 `World` 了。我去,异步加载个 js,替换这个页面,这样的操作应该几乎没有吧!所以,看起来百度的广告只能同步加载了,如果延迟加载(用个 `setTimeout` 方法)用到 `document.write` 的文件,那么理论上会覆盖整个页面吧,这是我们不希望看到的,也是我们要谨慎使用该方法的原因( `Why is document.write considered a “bad practice”?`)。 用 `document.write` 加载脚本文件,甚至还涉及到浏览器的兼容性,不同的浏览器会用不同的顺序加载,这点不展开了,有兴趣的可以参考如下链接: * 知乎 中张立理的回答 * `document.write` 方式引入外部 JS 文件导致脚本程序执行顺序不同以及 DOM 树更新延迟问题 * Javascript 装载和执行 最后总结下吧,如果用 `document.write` 来渲染页面,可以适当适时的使用,如果是加载脚本,尽量别用了,毕竟 `stevesouders` 建议别用([Don’t docwrite scripts][Don_t docwrite scripts]),主要还是为了不影响后续的加载。 附以前写的草稿: `document.write` 是 `document` 下的一个方法,很多入门书籍中经常见到该方法,实际生产中却很少用到。 `document.write()` 接收一个字符串作为参数,将该字符串写入文档流中。一旦文档流已经关闭(`document.close()`),那么 `document.write` 就会重新利用 `document.open()` 打开新的文档流并写入,此时原来的文档流会被清空,已渲染好的页面就会被清除,浏览器将重新构建 DOM 并渲染新的页面。 向文档流中写入 HTML 字符串: <div> <script> document.write("<script src='cm.js'><\/script>"); document.write("<div class='add'></div>") </script> </div> 因为 `document.write` 方法作用时,文档流还没关闭,所以并不用先 `document.open()`。渲染完后页面 `dom` 结构( chrome下 需考虑浏览器兼容性): <div> <script> document.write("<script src='cm.js'><\/script>"); document.write("<div class='add'></div>") </script> <script src="cm.js"></script> <div class="add"></div> </div> 这里还需要 注意一点,当 `document.write` 的字符串参数包含 `script` 标签时,注意要转义,或者将 `</script>` 割开(split),比如 `document.write("<script src='cm.js'></" + "script>");`,这是因为一旦遇到 `</script>`,会自动与包裹该段代码的 `<script>` 进行配对。详见 这里。 再看个例子: <div> <p>hello world</p> </div> <script> setTimeout(function() { document.write('<a href="http://www.cnblogs.com/zichi/">zichi\'s blog</a>'); }, 0); </script> 因为当 `setTimeout` 的回调执行时,文档流已经关闭(页面已经解析完),所以首先自动调用 `document.open()` 函数打开文档流,然后将文档流清空,渲染新的东西,即字符串中的 `a` 标签。 既然不加 `document.open()` 也会自动开启文档流,那么 `document.open()` 以及 `document.close()` 是否没用武之地了呢?思考如下代码。 代码一: <div> <p>hello world</p> </div> <script> setTimeout(function() { document.write('a'); document.write('b'); }, 0); </script> 代码二: <div> <p>hello world</p> </div> <script> setTimeout(function() { document.open(); document.write('a'); document.close(); document.open(); document.write('b'); document.close(); }, 0); </script> 前者页面显示 “`ab`”,而后者显示 “`b`”。可以想象前者两个 `document.write` 在一个文档流中输出,而后者手动关闭文档流,所以相当于重写了两次。 继续看: <div> <p>hello world</p> </div> <script> document.open(); document.write('a'); document.close(); document.open(); document.write('b'); document.close(); </script> 页面上 “`hello world`” 和 “`ab`” 都在。可以想象,当页面初次载入,浏览器还没解析完时,就算手动关闭文档流,也是关不掉的。 [20201116175021427.png]: /images/20210704/9101f97d4c66415aada6fd9856ac541d.png [Don_t docwrite scripts]: https://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/
相关 JavaScript面试题-documentwrite 和 innerHTML 的区别? document.write 和 innerHTML 的区别 主要区别:document.write 是直接将内容写入页面的内容流,会导致页面全部重绘,innerHTML 我会带着你远行/ 2023年06月14日 14:56/ 0 赞/ 26 阅读
相关 闲扯原码、反码、补码 相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念, 「爱情、让人受尽委屈。」/ 2022年09月30日 14:52/ 0 赞/ 77 阅读
相关 因一段JavaScript代码引发的闲扯 前两天,一朋友给我发了一段JavaScript代码: function f1(){ var n=999; nAdd=function 电玩女神/ 2022年08月01日 13:43/ 0 赞/ 186 阅读
相关 S2SH项目闲扯 1、jsp页面有显示当前时间的需求了,于是了解了下,发现了一个很简单实用的方法: 在页面开始加上:<%@taglib prefix="fmt" uri="http://jav 我会带着你远行/ 2022年07月16日 12:47/ 0 赞/ 130 阅读
相关 【闲扯】shell 获取不到返回值? 背景 这个问题,有点让人蛋疼了。具体是要获取ntpdate 同步返回的数据,用于判断ntpdate 是否执行成功。。。。 但是shell愣是拿不到返回数据,明明界面有 川长思鸟来/ 2021年10月29日 15:44/ 0 赞/ 530 阅读
相关 闲扯 『 document.write 』 初春的晚上,闲来无事,聊聊 `document.write` 方法。 `document.write` 使用方式非常简单,把 “字符串化”(不好意思,这可能是我自己创造的名词 男娘i/ 2021年07月05日 02:44/ 0 赞/ 440 阅读
还没有评论,来说两句吧...