DOM渲染是否在单个(同步)函数执行期间被禁止阻止?

rub*_*ruy 7 javascript dom html-rendering

DOM阻塞是许多人不熟悉JavaScript严格的单线程同步执行模型的事情,但是它通常只是我们想以某种方式解决的问题(使用超时,网络工作者等).一切都很好.

但是,我想知道阻止实际的用户可见渲染是否可以实际依赖.我90%肯定在大多数浏览器中事实上都是如此,但我希望这不仅仅是一个快乐的一致事故.我似乎无法从DOM规范或MDM等供应商文档中找到任何明确的陈述.

令我担心的是,虽然看到页面的DOM更改确实不可见,但内部DOM几何(包括CSS转换和过滤器)在同步执行期间确实会更新.例如:

console.log(element.getBoundingRect().width);
element.classList.add("scale-and-rotate");
console.log(element.getBoundingRect().width);
element.classList.remove("scale-and-rotate");
Run Code Online (Sandbox Code Playgroud)

......确实将报告两个不同的宽度值,虽然页面不会出现闪烁.在添加类(使用while循环)后同步等待也不会使临时更改可见.在Chrome中执行时间轴跟踪显示内部绘制和重新绘制正在发生相同,这是有道理的...

我担心的是,缺乏一个特定的原因,一些浏览器,比如那些处理动力不足的移动CPU的浏览器,可能会选择该功能的执行过程中实际反映用户可见布局中的那些内部计算,从而导致丑陋在此类临时操作期间"闪现".所以,更具体地说,我要问的是:他们有特定的理由不这样做吗?

(如果你想知道为什么我会关心这一点,我有时需要使用getBoundingRect某个状态的元素来计算计算尺寸,以计划间距或动画或其他类似的东西,而不是实际将它们置于该状态或首先为它们设置动画. ..)

Con*_*Fan 6

根据各种消息来源,获取 DOM 元素的位置或大小将在必要时触发输出的回流,以便返回的值是正确的。事实上,offsetHeight正如Alexander SkutinDaniel Norton所报告的那样,读取元素的 已成为强制回流的一种方式。

Paul Irish列出了导致回流的几种行为。其中包括这些元素框度量方法和属性:

  • elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight,
  • elem.offsetParent elem.clientLeft, elem.clientTop, elem.clientWidth,
  • elem.clientHeight elem.getClientRects(), elem.getBoundingClientRect()

Stoyan Stefanov描述了浏览器用于优化回流的策略(例如排队 DOM 更改并批量执行它们),并添加以下注释:

但有时脚本可能会阻止浏览器优化回流,并导致它刷新队列并执行所有批量更改。当您请求样式信息时会发生这种情况,例如

  1. offsetTop、offsetLeft、offsetWidth、offsetHeight
  2. 滚动顶部/左侧/宽度/高度
  3. 客户端顶部/左侧/宽度/高度
  4. getComputedStyle() 或 IE 中的 currentStyle

以上所有这些本质上都是请求有关节点的样式信息,并且无论何时执行此操作,浏览器都必须为您提供最新的值。为此,它需要应用所有计划的更改、刷新队列、咬紧牙关并进行回流。


ric*_*mer 2

Javascript 中没有任何与并发相关的东西是事实上的。JS根本就没有定义并发模型。一切都是幸福的偶然,还是多年的共识。

也就是说,如果你的函数没有调用任何奇怪的东西,比如 XMLHttpRequest 或“alert”或类似的东西,你基本上可以将它视为单线程,没有中断。