一. 前言
事件循环-eventloop前端笔试中的高频考点,了解事件循环也可以更好的理解代码底层运行机制,夯实基本功,比如下面这一段代码:
console.log(1);
setTimeout(function () {
console.log(2);
}, 2000);
console.log(3);
// 输出结果 1 3 2
输出的结果毫无疑问: 1 3 2
那么下面一段代码呢?
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
console.log(3);
// 输出结果 1 3 2
输出的结果还是 : 1 3 2 ,那么这是为什么呢?
二. 同步与异步
众所周知jS是单线程的,也就是说,事情只能一件一件的做,但是有些任务是耗时的,会阻塞代码的执行,为了解决这个问题,我们有了同步
和异步
的概念。
这样我们就可以把代码分为同步代码(同步任务)和异步代码(异步任务),比如上面的例子我们可以向下面这样拆分:
// 同步代码
console.log(1);
console.log(3);
// 异步代码
setTimeout(function () {
console.log(2);
}, 2000);
同步代码
:立即放入JS引擎(JS主线程)执行,并原地等待结果。
异步代码
:先放入宿主环境(浏览器/Node),不必原地等待结果,并不阻塞主线程继续往下执行,异步结果在将来执行。
所以输出的顺序是 1 3 2
执行过程:
同步代码放到执行栈中立即执行,而异步代码先会存放到宿主环境中,当达到触发条件后,就会将这个异步任务推送给任务队列(推送回调函数),当执行栈执行完毕后就会去任务队列中拉取其中的任务进行执行,这个去任务队列中拉取异步任务的过程就是事件循环
。
常见的异步任务:
除了,setTimeout,常见的异步代码还有 setInterval、Ajax/Fetch、事件绑定、promise里面then和catchl,他大致的共同点就是都是耗时的。
三. 宏任务与微任务
通过上一章的讲解,我们可以把代码分为同步代码(同步任务)和异步任务(异步任务),而在JS中我们又可以把异步任务分为宏任务
与微任务
,在ES5之后,JavaScript引入了Promise,这样,不需要浏览器,JavaScripti引擎自身也能够发起异步任务了。
宏任务是由宿主(浏览器、Node)发起:
任务(代码) | 任务类型 | 环境 |
---|---|---|
script | 宏任务 | 浏览器 |
事件 | 宏任务 | 浏览器 |
网络请求(Ajax/Fetch) | 宏任务 | 浏览器 |
setTimeout和setInterval(定时器) | 宏任务 | 浏览器 |
微任务JS引擎发起的任务:
任务(代码) | 任务类型 | 环境 |
---|---|---|
Promise | 微任务 | JS引擎 |
值得注意的是
:Promise本身同步,then/catch的回调函数是异步的。
那么代码的类型就可以细分为三类:
- 同步代码(JS执行栈/回调栈)
- 微任务的异步代码(JS引擎),常见的有 process.nextTick、Promise.then()catch()、Async/Await、Object.observe 等等
- 宏任务的异步代码(宿主环境),script(代码块)、setTimeout/setinterval定时器、setlmmediate定时器
执行过程:
同步代码放到执行栈中立即执行,异步任务分为宏任务与微任务分别存放到宏任务队列
和微任务队列
,执行栈中的同步代码执行完毕后,去微任务队列中拉取微任务放到执行栈中执行(先进先出原则),微任务队列中的任务执行完毕后,再去宏任务队列(先进先出)中拉取任务到执行栈中执行,直达执行完毕。
例如下面的例子:
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
const p = new Promise((resolve, reject) => {
console.log(3);
resolve(1000) // 标记成功
console.log(4);
})
p.then(data => {
console.log(data);
})
console.log(5);
执行栈同步任务:
console.log(1);
console.log(3);
console.log(4);
console.log(5);
微任务队列:
data => {
console.log(data);
}
宏任务同步队列:
function () {
console.log(2);
}
所以最后的执行结果是: 1 3 4 5 1000 2