是innerHTMLasynchronous?
我希望我不会愚弄自己,但是我正试图理解这两行代码中发生的事情:
document.body.innerHTML = 'something'; alert('something else');
我正在观察的是,HTML更新之前的警报显示(或者它已经有了,但是页面还没有被刷新/重新绘制/不pipe)
检查这codepen看看我的意思。
请注意,即使将alert
置于setTimeout(..., 0)
也无济于事。 看起来像更多的事件循环innerHTML
实际更新页面。
编辑:
我忘了提及我正在使用Chrome浏览器,并没有检查其他浏览器。 看起来像只在Chrome中可见。 不过,我仍然感兴趣为什么会发生这种情况。
设置innerHTML是同步的,您可以对DOM进行大部分更改。 但是, 呈现网页是一个不同的故事。
(请记住,DOM代表“文档对象模型”,它只是一个“模型”,是数据的表示,用户在屏幕上看到的是模型的外观,所以改变模型并不是瞬间的改变图片 – 需要一些时间来更新。)
运行JavaScript并渲染网页实际上是分开进行的。 简单地说,首先运行页面上的所有JavaScript(从事件循环 – 请查看此优秀video以获取更多详细信息),然后浏览器呈现对网页的任何更改以供用户查看。 这就是为什么“阻塞”是如此重要的原因 – 运行计算密集型代码可以防止浏览器越过“运行JS”步骤,进入“呈现页面”步骤,从而导致页面冻结或结束。
Chrome的pipe道看起来像这样:
正如你所看到的,所有的JavaScript都是首先发生的。 然后页面被devise,布置,绘画和合成 – “渲染”。 并不是所有的这个pipe道都会执行每一帧。 这取决于哪些页面元素发生了变化(如果有的话),以及如何将它们重新渲染。
注意: alert()
也是同步的,并在JavaScript步骤中执行,这就是在看到网页更改之前,警报对话框出现的原因。
你现在可能会问:“等一下,在stream水线里的'JavaScript'步骤究竟运行了什么?我的代码每秒运行60次吗? 答案是“否”,它回到JS事件循环的工作方式。 JS代码只在堆栈中运行 – 从事件监听器,超时等等。 看到以前的video (真的)。
https://developers.google.com/web/fundamentals/performance/rendering/
是的,它是同步的,因为这是有效的(继续,在你的控制台中input):
document.body.innerHTML = 'text'; alert(document.body.innerHTML);// you will see a 'text' alert
您看到页面更改之前看到警报的原因是浏览器呈现需要更多的时间,并且不像您的JavaScript逐行执行那样快。
innerHTML
属性actual会同步更新,但这种更改引起的可视化重绘是asynchronous发生的。
在Chrome中可视化呈现DOM是asynchronous的,直到当前的JavaScript函数堆栈清除并且浏览器可以自由接受新事件之后才会发生。 其他浏览器可能使用单独的线程来处理JavaScript代码和浏览器呈现,或者当警报停止另一个事件的执行时,它们可能会让某些事件优先。
你可以通过两种方式看到:
-
如果你在alert之前添加
for(var i=0; i<1000000; i++) { }
,你已经给浏览器足够的时间来重绘,但是没有,因为函数堆栈没有清除add
仍在运行)。 -
如果你通过一个asynchronous的
setTimeout(function() { alert('random'); }, 1)
延迟你的alert
,那么重绘过程将会超过被setTimeout延迟的函数。- 如果您使用
0
的超时时间,则这不起作用,可能是因为Chrome在其他任何事件(或至less在重绘事件之前)将事件队列优先级设置为0
超时。
- 如果您使用