❝最近我们前端团队在做技术分享,自己一直想讲讲Event Loop,于是研究了两天,发现自己之前有很多知识点都遗漏了,所以记录下来,与大家分享。
❞
在讲EventLoop之前,首先得搞明白几个概念。
1 同步和异步
同步和异步的概念相信各位大佬已经很熟悉了,但为了刚入行的同学着想,还是说明一下:
1.1 同步
如果在一个函数返回的时候,调用者就能够得到预期结果,那么这个函数就是同步的。 也就是说同步方法调用一旦开始,调用者必须等到该函数调用返回后,才能继续后续的行为。
1.2 异步
比如发一个请求,我们告诉主程序等到接收到数据后再通知我,然后我们就可以去做其他的事情了。当异步完成后,会通知到我们,但是此时可能程序正在做其他的事情,所以即使异步完成了也需要在一旁等待,等到程序空闲下来才有时间去看哪些异步已经完成了,再去执行。
「大白话总结:同步需要等待,一个执行完再执行另一个;异步不需要等,可以同时进行。」
2 宏任务和微任务
2.1 宏任务
宏任务指执行栈中待执行的任务,计时器,事件回调,http回调都是宏任务,比如以下几种,其中咱们最常用的就是setTimeout和setInterval。

2.2 微任务
微任务指执行栈清空后立即执行的任务(可以理解为VIP通道~),Promise 和 MutationObserver都是微任务,其中最常用的就是Promise。

2.3 优先级细节
宏任务macrotask: 主代码块 > setImmediate > MessageChannel > setTimeout / setInterval
微任务microtask: process.nextTick > Promise = MutationObserver
就是说任务执行的顺序是建立与优先级之上的: 如果队列已经有一个setTImeout的宏任务,后来又加入了主代码的宏任务,会让主代码的的任务插队。
「牢记一点:微任务优先执行,接下来是宏任务」

3 promise
promise本身是同步的,promise的then方法和catch方法才是异步的,我们举个栗子:
console.log(1)
let a = new Promise((res,rej) => {
console.log(2);
});
console.log(3);
let b = new Promise((res,rej) => {
console.log(4);
});
console.log(5);
输出是什么呢?1,3,5,2,4吗?
答案是:1,2,3,4,5

4 Event Loop
好了,终于进入了主题!先说说Event Loop是什么意思。
Event Loop就是JavaScript的事件循环,它指的是计算机系统的一种运行机制。JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。
- 接下来我们来做几道题。
setTimeout(() => {
console.log('1');
}, 0);
var obj = {
func: function() {
setTimeout(function() {
console.log('2');
}, 0);
return new Promise(function(resolve) {
console.log('3');
resolve();
});
},
};
obj.func().then(function() {
console.log('4');
});
console.log('5');
【解析】
第一个 setTimeout 放到宏任务队列,此时宏任务队列为 ['1']
接着执行 obj 的 func 方法,将 setTimeout 放到宏任务队列,此时宏任务队列为 ['1', '1']
函数返回一个 Promise,因为这是一个同步操作,所以先打印出 '3'
接着将 then 放到微任务队列,此时微任务队列为 ['4']
接着执行同步任务 console.log('5');,打印出 '5'
因为微任务优先执行,所以先输出 '4'
最后依次输出 '1' 和 '2'
- 最后再看一道经典考题,做好准备:
function async1() {
console.log('1');
Promise.resolve(async2()).then(() => {
console.log('2');
});
}
function async2() {
console.log('3');
}
console.log('4');
setTimeout(function() {
console.log('5');
}, 0);
async1();
new Promise(function(resolve) {
console.log('6');
resolve();
}).then(function() {
console.log('7');
});
console.log('8');
【解析】
首先打印出 '4'
接着将 settimeout 添加到宏任务队列,此时宏任务队列为 ['5']
然后执行函数 async1,先打印出 '1',又因为 Promise.resolve(async2()) 是同步任务,所以打印出 '3',接着将 '2' 添加到微任务队列,,此时微任务队列为 ['2']
接着打印出 '6',将 '7' 添加到微任务队列,,此时微任务队列为 ['2', '7']
打印出 '8'
因为微任务优先级高于宏任务,所以先依次打印出 '2' 和 '7'
最后打印出宏任务 '5'
怎么样,现在再做是不是感觉到比较轻松了呢。
关于作者:JeremyCC
一个爱唱歌的前端工程狮,喜欢我可以点关注噢!(头像仅供参考,哈哈)