JavaScript的事件循环机制是基于单线程执行的,这意味着JavaScript引擎在执行代码时,同一时间只能处理一个任务。为了处理I/O密集型或异步操作,JavaScript使用了事件循环(Event Loop)来管理任务队列和执行顺序。以下是JavaScript事件循环机制的基本组成部分:
任务被分为两大类:同步任务和异步任务。
- 同步任务(Synchronous Tasks):这些任务是按照代码的顺序依次执行的,它们会阻塞主线程,直到任务完成。
- 异步任务(Asynchronous Tasks):这些任务不会立即执行,而是会在将来的某个时间点执行。异步任务进一步分为宏任务(Macrotasks)和微任务(Microtasks)
常见的异步任务有如下几种
- Promise.then() ---微任务
- async/await ---Promise的语法糖 ---微任务
- setTimeout() ---宏任务
- setInterval() ---宏任务
事件循环流程
-
执行同步代码:
- JavaScript引擎开始执行主线程上的同步代码。
- 在执行同步代码的过程中,如果遇到异步操作(如setTimeout、Promise等),这些异步操作的回调函数不会被立即执行,而是根据它们的类型被放入相应的队列。
-
分类异步操作:
- 宏任务(Macrotasks) :这些通常是较大的任务,如定时器回调(setTimeout、setInterval)、IO操作、UI渲染等。当遇到宏任务时,它们的回调函数会被放入宏任务队列(也称为任务队列)。
- 微任务(Microtasks) :这些通常是较小的任务,如Promise的回调、MutationObserver等。当遇到微任务时,它们的回调函数会被放入微任务队列。
-
处理异步队列:
- 当主线程上的同步代码执行完毕后,JavaScript引擎会检查微任务队列。
- 如果微任务队列中有任务,那么这些微任务会被依次执行,直到微任务队列为空。
- 在所有微任务执行完毕后,事件循环可能会进行UI渲染更新。
- 接着,事件循环会检查宏任务队列,并从宏任务队列中取出一个宏任务执行。
- 执行完一个宏任务后,再次回到步骤3,首先检查并执行微任务队列中的任务。
这个过程会不断重复,形成事件循环。以下是一个简化的流程图:
执行同步代码
|
V
遇到异步操作 -> 放入宏任务队列或微任务队列
|
V
同步代码执行完毕
|
V
检查并执行微任务队列中的所有微任务
|
V
可能进行UI渲染更新
|
V
从宏任务队列中取出一个宏任务执行
|
V
回到步骤2,继续事件循环