宏任务:
整体 script, setTimeout, setInterval,UI交互事件,setImmediate(Node.js)
微任务:
Promise, process.nextTick(Node 版 setTimeout,在event loop 的下一次循环中调用回调函数)
ps: 我个人觉得用宏任务和微任务来理解promise,和异步更好。
首先js的执行顺序是:
进入整体代码(宏任务)后,开始第一次循环, 执行宏任务,宏任务执行完毕,再执行所有的微任务,
然后再次下一个宏任务开始,宏任务执行完毕,再执行微任务
也就是:
宏 微 宏 微。。。一直循环
ps: 本人是在这个博客 EventLoop不可怕,可怕的是遇到Promise里面看到,然后写下自己的心得,大家也可以去这个博客里面看。
讲了这多,开始宏任务与微任务,直接拿出代码:
setTimeout(function () {
console.log('setTimeout');
})
new Promise(function (resolve) {
console.log('promise');
resolve();
}).then(function () {
console.log('then');
})
console.log('console');
一个很典型的宏与微任务:
1. 首先重 main script(也就是script 代码,第一轮宏任务开始),遇到了setTimeout,仍入下一轮的宏任务
2. Promise内部正常执行,输出 promise, 直接 resolve()了, .then() 作为一个微任务,进入微任务队列
3. 遇到console.log(), 直接输出 console
到这里,第一轮宏任务执行完毕,开始执行第一轮微任务
输出 then, 微任务执行完毕了,然后执行下一轮的宏任务,也就是输出了 setTimeout
结果是: promise console then setTimeout
来个复杂点的
大家先记住,一个微任务里面产生的新的微任务,是在当前微任务队列的后面添加,而不是下一轮的微任务。
setTimeout(() => { // 宏1
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => { // 微1
console.log(3);
new Promise( (res) => {
console.log(6);
res(); // 直接res 了,.then() 回调进入当前微任务的后面,也就是它.then()现在属于 第一轮微任务的第二个任务
})
.then( () => {
console.log(7);
});
// 隐式返回了一个promise,也是进入当前微任务队列的后面,也就是第一轮微任务的第三个任务
}).then(() => {
// 这个代码执行完毕,微任务队列被清空了,开始第二轮宏任务,也就是setTimeout 的回调
console.log(4)
})
console.log(5);
// 2 5 3 6 7 4 1,我的注释就直接写代码旁边了