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 以允许浏览器运行一轮事件循环。
附加细节:
似乎有一种特殊情况会触发昂贵的回流。请注意,回流是浏览器计算页面布局。如果浏览器需要绘制更改的页面,通常会触发它。
当页面中的某些内容发生更改时,回流计算会排队 - 不会立即执行。与上面的描述一样,回流只会在 javascript 执行结束时执行。但是有一种情况会导致浏览器立即执行回流计算:如果您尝试读取任何计算值,例如宽度和高度。
有关更多信息,请参阅此相关问题:在 DOM 环境中何时发生回流?