初春的晚上,闲来无事,聊聊 document.write 方法。javascript
document.write 使用方式很是简单,把 "字符串化"(很差意思,这多是我本身创造的名词)的 html 代码当作参数传入就 ok 了,我并不打算讲它的基本用法,能够参考如下连接:html
document.write 常常会被用来加载脚本,好比这样:java
var url = 'http://ads.com/buyme?rand='+Math.random() document.write('<script src="'+url+'"></scr'+'ipt>')
传统方式:jquery
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)。可是,若是这段脚本没有执行完,后续渲染都将挂起!ajax
document.write 加载脚本也不是没有合适的场景,好比说后续的渲染都要依赖这段脚本,那么这样写就彻底没有问题。好比这段代码:chrome
<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>
或者:shell
<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>
很是的优雅。json
还有个应用场景,加载第三方广告,百度联盟的广告就是用该方法输出的。咱们假设百度联盟广告以下(另存为 cm.js):api
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):
按照 notice 的提示将 document.open() 加入 data.js 文件,这时页面就只有 World 了。我去,异步加载个 js,替换这个页面,这样的操做应该几乎没有吧!因此,看起来百度的广告只能同步加载了,若是延迟加载(用个 setTimeout 方法)用到 document.write 的文件,那么理论上会覆盖整个页面吧,这是咱们不但愿看到的,也是咱们要谨慎使用该方法的缘由( Why is document.write considered a “bad practice”?)。
用 document.write 加载脚本文件,甚至还涉及到浏览器的兼容性,不一样的浏览器会用不一样的顺序加载,这点不展开了,有兴趣的能够参考以下连接:
最后总结下吧,若是用 document.write 来渲染页面,能够适当适时的使用,若是是加载脚本,尽可能别用了,毕竟 stevesouders 建议别用(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" 都在。能够想象,当页面初次载入,浏览器还没解析完时,就算手动关闭文档流,也是关不掉的。