document.write的用处

document.write是JavaScript中对document.open所开启的文档流(document stream操作的API方法,它能够直接在文档流中写入字符串,一旦文档流已经关闭,那document.write就会重新利用document.open打开新的文档流并写入,此时原来的文档流会被清空,已渲染好的页面就会被清除,浏览器将重新构建DOM并渲染新的页面。

写入文本

下面来看看如何在利用document.write来写入脚本。先考虑如下代码:

<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<h1>Head</h1>
<script>
document.write('<p>hello document</p>');
</script>
<h2>Tail</h2>
</body>
</html>

这段在h1h2之间内嵌一个脚本,使用document.write来写入一个p标签。

刷新页面,可以看到最终的结果是

Head

hello document

Tail

即要文本在脚本执行的位置被插入。这是因为,浏览器就解析HTML构建DOM的时候,如果遇到script就会暂停下来,解析script中的代码并执行,然后再继续解析剩余HTML。

此时再去浏览器中检测DOM的结构,会发现scripth2之间多了一个p,浏览器在解析完h1之后,碰到script并执行之,此时document.write将一段HTML代码写入到文档流中,script执行完毕后,浏览器会解析文档流中的字符串,对新添加的p标签进行解析。

如果将渲染好的页面保存下来,不同的浏览器会有不同的结果。如Chrome和Firefox的做保存下来的页面文件中,script后面会增加p标签,而IE中则是维持原状。(这里指的是原有的HTML结构,不同浏览器将页面保存会作不同的处理,有些会增加一些不影响原有结构的标签或注释。这意味着,如果浏览器重新加载Chrome或Firefox中保存下来的页面文件,就会多出一个p标签。

写入脚本

既然document.write可以写入p并被浏览器解析,那么自然地也可以写入script标签。

<script>
document.write('<script>alert("oops!!!")</script>');
</script>

我们将代码作出上面的改动,意图在利用document.write在页面中插入一段脚本。这段代码的本意是弹出一个窗口,阻塞浏览器对HTML的解析。

浏览器下刷新页面,发现并不管用,取而代之的是显示出一个没有意料到的页面。

Head

');
Tail

去检查DOM树,就会发现,这段脚本被拦腰截断了!浏览器将它解析成以下代码:

<script>
document.write('<script>alert("oops!!!")
</script>
');

插入文本中的</script>被当成了第一个script的闭合标签,因此这个段代码成了非法代码,因为document.write的调用书写不正确,缺少右边的括号)。此时,你可以在console中看到相关的错误信息。

为了解决这个问题,我们可以对插入文本中闭合的的标签进行轻微修改,对最后一个>进行转义,变成\>

此时再刷新一下页面,就可以看到预想中的结果。即页面中仅显示h1,弹窗阻塞了浏览器对HTML的解析,关闭弹窗后,浏览器继续对HTML的解析并完成对页面的渲染。

再去看看DOM的结构,会发现在原有的script元素后面又多了一个新的<script>元素,其中所执行的代码就是我们的alert("opps!!!")

document.write使用的时机很重要

这样看来,利用document.write来在HTML中插入标签非常方便,就如同让浏览器在解析HTML的时候动态得添加标签,而且只需要一行代码即可,不需要使用document.createElement再将其插入到DOM中。

但为什么大家都不建议使用document.write呢?这跟document.write的实现机制有关。在讨论之前,先看看下面的代码:

<script>
setTimeout(function(){
document.write('<p>5 secs later</p>');
}, 5000);
</script>

对之前的代码作简单修改,这段代码同样是想插入一个p元素,但它是在5秒以后才执行。

刷新页面后,我们看到了这样的显示效果:

Head

Tail

但是5秒以后,页面却变成了这样:

5 secs later

原来的h1h2甚至是scriptDOCTYPE还有head(当然,之前并没有往head添加任何标签,但如果添加了,这些标签也会有同样的下场),它们全部都不见了,取而代之的是一个基本的html结构,它是这样的:

<html>
<head></head>
<body>
<p>5 secs later</p>
</body>
</html>

这是一个全新的页面,document.write将之前的页面全部清除了,重新打开一页面并在这个页面上写入了新的标签。为什么会这样呢?

回到再文章开头所描述文字,就会找到结果。这是因为,5秒以后,浏览器早已完成了HTML的解析,并将文档流给关闭了。5秒后,timeout事件触发,document.write在执行的时候发现文档流已经关闭了,就会重新调用document.open打开一个新的文档流,而document.open的调用则会清除已有的文档。所以,最终看到的显示结果就是向上面那样,之前存在的页面都被清除掉了。

如果我们把document.write调用放到DOMCOntentLoadedload的事件处理中,也会得到同样的结果。

这样看到,除非是在浏览器关闭文档之前调用document.write,否则当前页面都会被清除。

这一个特性决定了document.write在实际开发中的应用范围和时机。那么,什么时候应该使用document.write呢?

在网上搜集的资料看,一般在下列情景下可以利用document.write来完成某些特殊的操作:

加载需要配合JS脚本使用的外部CSS文件

利用下面的语句加载外部样式文件:

<scirpt>
document.write('<link rel="stylesheet" href="style_neads_js.css">');
</script>

将所有需要用到JS的样式都放到这个外部样式表中,如果浏览器不禁用JS,那么该样式表就会被顺利加载,否则页面就不会使用该样式。(Don’t docwrite scripts

在新的窗口中写入新的页面数据时

既然在一个已加载完成的页面中调用document.write会重写整个页面,那么在一个新的窗口的空白页面中调用这个方法,就不存在这样的的问题了。

另外,在调用document.write,最好不要把document.opendocument.close漏掉,尽管多数时候浏览器会帮忙完成这些操作。即,一个标准的document.write应该是这样的:

document.open();
document.write('anthing')
document.close();

弊端

从某个角度说,document.write的实际功能确实很强,能够直接修改文档流,但它有很多弊端:

  • 在非loading阶段调用document.write会清除已加载的页面;
  • document.write不能够在XHTML中使用
  • 嵌入script中的document.write不能给任意节点添加子节点,因为它是随着DOM的构建执行的;
  • 利用document.write写入HTML字符串流并不是一个好方法,它有违DOM操作的概念;
  • 利用document.write添加script加载外部脚本时,浏览器的HTML解析会被script的加载所阻塞;

总结

综合上面所描述的关于document.write的种种特点,个人感觉还是不到迫不得已的时候,不要去使用document.write,使用不当document.write不仅会影响页面的性能,还容易造成各种bug。

要对DOM进行操作时,还是应当使用安全且对DOM的友好的API方法,以避免不必要的问题出现。

上述信息都是以自己做的小测试和网上的参考资料为基础总结出来,有错误的地方,欢迎大家指出,我会尽快作出修正。

参考

js中document.write的那点事

document.wrtie_MDN

Three JavaScript articles and one best practice

Don’t docwrite scripts

Why is document.write considered a “bad practice”?

【repost】document.write的用处的更多相关文章

  1. document.write的用处!

    document.write是JavaScript中对document.open所开启的文档流(document stream操作的API方法,它能够直接在文档流中写入字符串,一旦文档流已经关闭,那d ...

  2. 关于document.write

    document.write的用处 document.write是JavaScript中对document.open所开启的文档流(document stream操作的API方法,它能够直接在文档流中 ...

  3. NoSql数据库使用半年后在设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

  4. NoSql数据库使用半年后在设计上面的一些心得 (转)

    http://www.cnblogs.com/AllenDang/p/3507821.html NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我 ...

  5. NoSql数据库使用

    NoSql数据库使用半年后在设计上面的一些心得 NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么 ...

  6. Web前端教程3-JavaScript教程

    目录 1. JavaScript介绍 1.1. JS嵌入页面的方式 2. JS基本语法 2.1. 变量类型 2.2. 获取元素方法 2.3. 操作元素属性 2.4. innerHTML的使用 3. J ...

  7. 【笔记】JS脚本为什么要放在body最后面以及async和defer的异同点

    1.没有defer或async 浏览器遇到脚本的时候会暂停渲染并立即加载执行脚本(外部脚本),"立即"指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的 ...

  8. NoSql数据库 设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 用户信息表,书籍信息表,用户为书籍打分信 ...

  9. NoSql数据库使用半年后在设计上面的一些心得 (转载)

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

随机推荐

  1. react+redux教程(七)自定义redux中间件

    今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...

  2. 【Oracle 集群】Linux下Oracle RAC集群搭建之基本测试与使用(九)

    Oracle 11G RAC数据库安装(九) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总 ...

  3. DG gap sequence修复一例

    环境:Oracle 11.2.0.4 DG 故障现象: 客户在备库告警日志中发现GAP sequence提示信息: Mon Nov 21 09:53:29 2016 Media Recovery Wa ...

  4. Discuz X3.2 网站快照被劫持的解决方法

    附上另一个人的解决方法:http://www.discuz.net/thread-3549930-3-1.html 问题如下: 快照被劫持,无论怎么申诉,怎么更新快照,都无法消除此问题,第一次打开网站 ...

  5. 1元搭建自己的云服务器&解析域名

    最近在学做微信开发,没有自己的域名和服务器就不得不寄人篱下,索性自己就到云主机上搭建了个服务器,但是水平有限弄了一个下午~~有自己的域名和服务器的好处相信不用我多说了.比如日后可以有自己域名的个性博客 ...

  6. Hive索引功能测试

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 从Hive的官方wiki来看,Hive0.7以后增加了一个对表建立index的功能,想试下性能是 ...

  7. MyCat源码分析系列之——SQL下发

    更多MyCat源码分析,请戳MyCat源码分析系列 SQL下发 SQL下发指的是MyCat将解析并改造完成的SQL语句依次发送至相应的MySQL节点(datanode)的过程,该执行过程由NonBlo ...

  8. 针对每种Windows Server 操作Excel、Word等Office组件遇到“ComException"、”80070005“等COM错误的解决方案大汇总

    以下所有Excel错误的解决方案,同样适用于Word.PowerPoint等Office产品. 以下解决方案中,如果出现"安装Excel组件",是适用于遇到Excel错误的.如果是 ...

  9. iOS-多线程介绍

    一.前言部分 最近在面试,重新温习了一遍多线程,希望加深一遍对于多线程的理解. 1.什么是进程? 1).要了解线程我们必须先了解进程,通俗来讲进程就是在系统中运行的一个应用程序. 2).每个线程之间是 ...

  10. Python3.5安装及opencv安装

    Python安装注意事项(版本3.5,系统windows)1.安装好Python后将D:\Program Files\Python.D:\Program Files\Python\Scripts加入P ...