乐闻世界logo
搜索文章和话题

浏览器中的事件循环的工作流程

浏览17
6月24日 16:43

事件循环 (Event Loop) 是浏览器用于处理非同步事件的一种机制。它确保了 JavaScript 的执行能够同步进行,即使 JavaScript 是单线程运行的。下面是事件循环的工作流程:

  1. 执行栈(Call Stack): 当一段JavaScript代码开始执行时,它首先会进入到执行栈中。如果这段代码是一个函数,那么这个函数就会被放到栈的顶部。
  2. Web APIs: 当遇到非同步操作(如:setTimeout, XMLHttpRequest 等)时,该操作会被浏览器的Web APIs接管,执行栈会继续执行下一行代码,不会停下等待异步操作的结果。
  3. 任务队列(Task Queue): 一旦异步操作完成了(比如说 setTimeout 中指定的时间已过),回调函数就会被放入任务队列中。任务队列就是一个等待执行栈清空后执行的回调函数的列表。
  4. 事件循环: 事件循环的职责是监控执行栈和任务队列。如果执行栈为空,它就会检查任务队列。如果任务队列中有待执行的回调函数,事件循环就会将其从队列中取出,放到执行栈中去执行。
  5. 渲染队列(Render Queue): 当浏览器准备进行渲染时(通常是每16.7毫秒,对应于60fps),它会有自己的渲染队列来处理重绘和回流事件。如果执行栈和任务队列都是空的,事件循环会从渲染队列取出任务执行,以确保用户界面能够及时更新。
  6. 微任务队列(Microtask Queue): 除了常规的任务队列,还有一种叫作微任务(Microtask)的任务,比如Promise的回调。微任务队列的特点是在当前执行栈清空后,就会立即执行微任务队列中的所有任务,即使任务队列中有等待的任务。只有当微任务队列为空时,事件循环才会查看任务队列。

例子

假如我们有以下代码片段:

javascript
console.log('脚本开始'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('脚本结束');

执行顺序将会是这样的:

  1. '脚本开始' 被打印到控制台,因为它是第一行同步代码。
  2. setTimeout 的回调被 Web APIs 接管,执行栈继续往下执行。
  3. Promise.resolve() 创建了一个Promise,它的回调被放入了微任务队列。
  4. '脚本结束' 被打印到控制台,因为它是同步代码。
  5. 当前的同步代码已经执行结束,执行栈被清空。
  6. 事件循环首先检查微任务队列,发现有Promise的回调。
  7. 'promise1''promise2' 依次被打印到控制台。
  8. 微任务队列清空,事件循环现在检查任务队列。
  9. setTimeout 的回调现在被事件循环从任务队列移到执行栈,打印 'setTimeout'
标签:前端