我正在尝试制定一个有效的算法来更改一堆节点上的很多类,我发现我对javascript如何遍历DOM有一个很大的漏洞。
浏览器/ javascript是否使用像闪存一样的弹性赛道?或者它是更多的事件驱动,每次有变化时重绘整个显示?
“弹性赛道”是一个闪光范例,你可以想象一个闪烁的大循环。在用户处理期间,时间变化积累,并且在闪存处理期间,闪存引擎会四处奔跑并一遍又一遍地应用所有更改。
替代方案是一个事件模型,每次属性更改时,整个屏幕都会重新绘制 - 这可能是浏览器所做的,但我不确定。
我可以想到混合算法,如果没有任何变化,没有任何事情发生 - 但是如果它们被允许建立 - 有点像我的水槽上的菜肴。
有没有人能够快速描述用于处理属性更改和DOM插入的算法。
答案 0 :(得分: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
│ │ │
│ │ │
└────◀─────┴─────────────────◀─────────────────┘
正如他们所说,其余的都是历史。当Microsoft复制javascript时,他们必须复制事件循环以保持与Netscape兼容。因此,形式然后每个人都必须做同样的事情以保持与Netscape和IE兼容。
请注意,javascript没有任何功能可以手动递归到事件循环中(某些语言,例如tcl,可以这样做),因此浏览器必须等到重绘页面之前没有更多的javascript要执行。在脚本结束之前,不能强制进行页面重绘。
正是由于这个原因,当您尝试在创建后立即读取它们时,计算出的值(如元素的宽度或高度)有时会返回错误的值 - 浏览器尚未绘制它们。如果您真的需要在页面重绘后执行代码,那么解决方法是使用超时值为0的setTimeout
以允许浏览器运行一轮事件循环。
其他细节:
似乎有一种特殊情况会引发昂贵的回流。请注意,重排是浏览器计算页面布局。如果浏览器需要绘制更改的页面,通常会触发它。
当页面中的某些内容发生变化时,重排计算会排队 - 不会立即执行。如在上面的描述中,回流将仅在javascript执行结束时执行。但有一种情况会导致浏览器立即执行回流计算:如果您尝试读取任何计算值,例如宽度和高度。
有关详细信息,请参阅此相关问题:When does reflow happen in a DOM environment?