Event Loop
-
为什么要有Event Loop?
- 单线程限制:JavaScript 是单线程语言,所有任务需在主线程排队执行。
- 防止阻塞:异步任务(如网络请求、定时器)若直接执行会阻塞主线程,Event Loop 通过任务队列管理异步任务,确保主线程高效运行。
-
什么是Event Loop?
-
JavaScript有一个主线程和执行栈,所有任务都会被放在执行栈中等待主线程执行
- 主线程:唯一执行 JavaScript 代码的线程(执行同步任务)
- 执行栈:用于存储待执行的同步任务,按先进后出(FILO)的顺序执行
- 任务队列:分为宏任务队列和微任务队列,存放异步任务的回调
-
JavaScript单线程任务分为同步任务和异步任务
- 处理同步任务:在执行栈中按顺序等待主线程依次执行
- 处理异步任务:
- 在异步任务有结果之后,将注册的回调函数放入任务队列(宏任务或微任务)
- 等当前执行栈中的所有任务都执行完毕,此时主线程处于空闲状态,取出回调函数执行
-
任务队列分为宏任务和微任务
宏任务 微任务 script
代码块Promise.then/catch/finally
setTimeout/setInterval
queueMicrotask
I/O 操作
MutationObserver
UI 渲染
(浏览器)process.nextTick
(Node)-
执行流程
-
执行栈先执行当前宏任务(如
script
代码块) -
遇到同步任务立即执行;遇到异步任务则注册回调到对应队列
-
当前宏任务执行完毕后,检查微任务队列
- 若微任务队列非空,依次执行所有微任务,直到队列清空
-
执行下一个宏任务,循环此过程
-
-
-
举例:一个简易的Event Loop
console.log('start'); Promise.resolve().then(() => { console.log('promise'); }); setTimeout(() => { console.log('setTimeout'); }, 0); console.log('end');
-
执行步骤
- 宏任务
script
开始执行 - 输出
start
Promise.then
回调放入微任务队列setTimeout
回调放入宏任务队列- 输出
end
- 当前宏任务结束,清空微任务队列,输出
promise
- 取下一个宏任务(
setTimeout
),输出setTimeout
- 宏任务
-
输出结果
start end promise setTimeout
-
参考资料
https://juejin.cn/post/7024751918484291591
https://www.jianshu.com/p/de7aba994523
https://juejin.cn/post/6844903764202094606#heading-1