我有这个示例代码:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
</head>
<body>
<script>
var EventHandler = {};
EventHandler.writeNumber = function(i){
document.write(i);
};
for(var i=0; i<100; i++) {
(function(i) {
window.setTimeout(function() {
EventHandler.writeNumber(i);
},100*i);
}(i));
}
</script>
</body>
</html>
代码每秒在页面上写入一个数字。在Chrome 26和Safari 5中运行良好!在Firefox 18和IE10中,它只出现一次(0写在文档上)。
如果我将document.write
更改为console.log
,那么它适用于所有浏览器。为什么?
这是Chrome和Safari(或者更准确地说是WebKit)中的一个错误。当页面未处于解析中期时,document.write
意味着document.open
,而document.open
应该根据规范清除所有超时。IE和Firefox就是这样做的,但WebKit对document.open
的处理有点糟糕。
document.write
应该只在页面加载时工作一次。
页面从上到下进行解析。解析时发现的每一个JavaScript都会立即执行。当执行结束或被分派(setTimeout
或任何其他异步内容)时,浏览器继续解析。
当您执行document.write("Test")
时,解析器将直接在关闭的</script>
标记之后创建一个文本节点Test
,因为它当前正处于这个位置。如果用1ms的setTimeout
延迟,解析器将处于不同的点,请将文本节点插入页面下方。
如果等待太久,解析器将完成对页面的解析,不再接受写入。或者,在chrome的情况下,解析器试图修复程序员的错误,并保留对<script>
标记位置的引用,从而在实际解析完成后仍然可以使用document.write
。
使用控制台和Firebug(F12
)查看发生了什么。
一般来说,document.write
是一种非常糟糕的做法。它非常慢,因为解析器必须为每种HTML元素解析给定的字符串。请改用document.createTextNode
或document.createElement
。