4

我正在尝试制定一种有效的算法来更改一堆节点上的大量类,但我发现我对 javascript 如何遍历 DOM 的理解存在很大的漏洞。

浏览器/javascript 是否像 flash 一样使用弹性跑道?还是更多的事件驱动,每次发生变化时都会重新绘制整个显示?

“弹性跑道”是一种 flash 范例,您可以在其中想象一个 flash 循环的大循环。在用户处理期间,变化建立起来,在闪存处理期间,闪存引擎四处奔走并应用所有的变化——一遍又一遍。

另一种方法是事件模型,每次属性更改时都会重绘整个屏幕 - 这可能是浏览器所做的,但我不确定。

而且我可以想到混合算法,如果没有变化,什么也不会发生——但如果有的话,它们被允许堆积——有点像我水槽上的盘子。

有没有人快速描述用于处理属性更改和 DOM 插入的算法。

4

1 回答 1

6

Flash 的“弹性跑道”继承自浏览器。当然,在浏览器领域我们不会这样称呼它——我们称之为事件循环。

javascript 事件循环的历史始于 Netscape 上的渐进式 GIF 和 JPEG 渲染。渐进式渲染 - 部分加载的内容的绘制 - 需要 Netscape 实现异步下载渲染引擎。当 Brendan Eich 实现 javascript 时,这个异步事件循环已经存在。因此,向其中添加另一层是一项相当简单的任务。

因此,浏览器的事件循环类似于以下内容:

    Event loop
        ┌──────────┐
        │          │
        │          │
        │          ▼
        │        check if there's any new ───────▶ parse data
        │        data on the network                    │
        │          │                                    │
        │          ▼                                    │
        │        check if we need to execute  ◀─────────┘
        │        any javascript ──────────────────▶ execute
        │          │                               javascript
        │          ▼                                  │
        │        check if we need to ◀────────────────┘
        │        redraw the page  ──────────────▶ redraw page
        │          │                                   │
        │          │                                   │
        └────◀─────┴─────────────────◀─────────────────┘

其余的,正如他们所说,是历史。当微软复制 javascript 时,他们不得不复制事件循环以保持与 Netscape 的兼容。所以窗体上每个人都必须做同样的事情来保持与 Netscape 和 IE 的兼容。

请注意,javascript 没有任何手动递归到事件循环的功能(某些语言,例如 tcl,可以这样做),因此浏览器必须等到没有更多的 javascript 执行后再重绘页面。在脚本结束之前不能强制进行页面重绘。

正是由于这个原因,当您在创建后立即尝试读取元素的宽度或高度等计算值时,有时会返回错误的值 - 浏览器尚未绘制它们。如果您确实需要在页面重绘后执行代码,解决方法是使用setTimeout超时值为 0 的 a,以允许浏览器运行一轮事件循环。


附加细节:

似乎有一种异常情况会触发昂贵的回流。请注意,重排是浏览器计算页面布局。如果浏览器需要绘制更改的页面,通常会触发它。

当页面中的某些内容发生更改时,回流计算会排队 - 不会立即执行。和上面的描述一样,reflow 只会在 javascript 执行结束时执行。但是有一种情况会导致浏览器立即执行回流计算:如果您尝试读取任何计算值,例如宽度和高度。

有关更多信息,请参阅此相关问题:何时在 DOM 环境中发生回流?

于 2013-10-27T15:53:16.947 回答