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 环境中发生回流?