了解Event Loop(事件循环)机制
作为前端面试八股文中最重要的一个知识点,每次被问到时总是不知从哪里说起,说的也不够完整,整理众多资料后记下笔记。
为什么会有事件循环(Event Loop)机制
大家都知道JavaScript是单线程的脚本语言,在同一时间,只能做同一件事,为了协调事件、用户交互、脚本、UI渲染和网络处理等行为,防止主线程阻塞,Event Loop方案应运而生…
JavaScript为什么是单线程的
JavaScript的主要用途是与用户互动,以及操作DOM。如果它是多线程的话会有很多复杂的问题要处理,比如有两个线程同时操作DOM,一个线程删除了当前的DOM节点,一个线程是要操作当前的DOM阶段,最后以哪个线程的操作为准?为了避免这种,所以JavaScript是单线程的。
事件循环的定义
在执行代码过程中,如果遇到一些异步代码(比如setTimeout,ajax,promise以及用户点击等操作),那么浏览器就会将这些代码放到另一个线程(在这里我们叫做幕后线程)中去执行,在前端由浏览器底层执行,在 node 端由 libuv 执行,这个线程的执行不会阻塞主线程的执行,主线程继续执行栈中剩余的代码。
当幕后线程(background thread)里的代码执行完成后(比如setTimeout时间到了,ajax请求得到响应),该线程就会将它的回调函数放到任务队列(又称作事件队列、消息队列)中等待执行。而当主线程执行完栈中的所有代码后,它就会检查任务队列是否有任务要执行,如果有任务要执行的话,那么就将该任务放到执行栈中执行。如果当前任务队列为空的话,它就会一直循环等待任务到来。这就是事件循环。
由上文任务队列引申出的其他概念
接上文,如果任务队列中,有很多个任务的话,那么要先执行哪一个任务呢?
其实js是有两个任务队列的,一个叫做 Macrotask Queue宏任务, 一个叫做 Microtask Queue微任务

在同步代码执行完成后,才会回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。
1 |
|
那些常见的宏任务和微任务
宏任务
ps:√表示为当前环境的api,✖表示非当前环境的api
名称 | 浏览器 | Node |
---|---|---|
I/O | √ | √ |
setTimeout | √ | √ |
setInterval | √ | √ |
setImmediate | ✖ | √ |
requestAnimationFrame | √ | ✖ |
微任务
名称 | 浏览器 | Node |
---|---|---|
process.nextTick(vue中的nextTick也是微任务) | ✖ | √ |
MutationObserver | √ | ✖ |
Promise.then catch finally | √ | √ |
常见的面试题
1 |
|
参考资料:
面试一定会问到的-js事件循环
详解JavaScript中的Event Loop(事件循环)机制
js事件循环
事件循环:微任务和宏任务
面试题:说说事件循环机制(满分答案来了)
微任务、宏任务与Event-Loop