是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代码和浏览器呈现,或者当警报停止另一个事件的执行时,它们可能会让某些事件优先。

你可以通过两种方式看到:

  1. 如果你在alert之前添加for(var i=0; i<1000000; i++) { } ,你已经给浏览器足够的时间来重绘,但是没有,因为函数堆栈没有清除add仍在运行)。

  2. 如果你通过一个asynchronous的setTimeout(function() { alert('random'); }, 1)延迟你的alert ,那么重绘过程将会超过被setTimeout延迟的函数。

    • 如果您使用0的超时时间,则这不起作用,可能是因为Chrome在其他任何事件(或至less在重绘事件之前)将事件队列优先级设置为0超时。