原文链接:https://blog.csdn.net/NancyFyn/article/details/118407548
1.宏任务和微任务是什么?
js是一种单线程语言,简单的说就是只有一条通道,在任务多的情况下,就会出现拥挤的情况,这种情况下就产生’多线程’,但是这种“多线程”是通过单线程模仿的,也就是假的,那么也就产生了同步任务和异步任务
2.宏任务和微任务有哪些
宏任务:
- script (可以理解为外层同步代码)
- setTimeout/setInterval
- UI rendering/UI事件
- postMessage,MessageChannel
- setImmediate,I/O(Node.js)
微任务: - Promise
- process.nextTick(Node.js)
- Object.observe(已废弃;Proxy 对象替代)
- MutaionObserver
3. 宏任务和微任务是怎么执行的?*****
执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕之后,再将异步微任务从队列中调入主线程执行,微任务执行完毕之后再将异步宏任务从队列中调入主线程中执行,一直循环直至所有任务执行完毕
同步任务异步微任务=异步宏任务=====
这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是先执行同步任务,异步任务有宏任务和微任务两种,先将宏任务添加到宏任务队列中,将宏任务里面的微任务添加到微任务队列中。所有同步执行完之后执行异步,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行。之后就一直循环
4.案例
setTimeout(function(){ // 异步宏任务5
console.log('1');
});
new Promise(function(resolve){ // 同步任务 1
console.log('2');
resolve();
}).then(function(){ // 异步微任务3
console.log('3');
}).then(function(){ // 异步微任务4
console.log('4')
});
console.log('5'); // 同步任务2
// 2 5 3 4 1
//分析:
// 1.遇到setTimout,异步宏任务,放入宏任务队列中
// 2.遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2
// 3.而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
// 4.遇到同步任务console.log(‘5’);输出5;主线程中同步任务执行完
// 5.从微任务队列中取出任务到主线程中,输出3、 4,微任务队列为空
// 6.从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空
例2:
setTimeout(()=>{ // 异步宏任务
new Promise(resolve =>{ // 同步6
resolve();
}).then(()=>{ // 异步微任务8
console.log('test');
});
console.log(4); // 同步7
});
new Promise(resolve => { // 同步1
resolve();
console.log(1)
}).then( () => { // 异步微任务 3
console.log(3);
Promise.resolve().then(() => { // 异步微任务4
console.log('before timeout');
}).then(() => { // 异步微任务
Promise.resolve().then(() => { // 异步微任务5
console.log('also before timeout')
})
})
})
console.log(2); //同步2
/// 1 2 3 before timeout also before timeout 4 test
分析:
1.遇到setTimeout,异步宏任务,将() => {console.log(4)}放入宏任务队列中;
2.遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出1;
3.而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
4.遇到同步任务console.log(2),输出2;主线程中同步任务执行完
5.从微任务队列中取出任务到主线程中,输出3,此微任务中又有微任务,Promise.resolve().then(微任务a).then(微任务b),将其依次放入微任务队列中;
6.从微任务队列中取出任务a到主线程中,输出 before timeout;
7.从微任务队列中取出任务b到主线程中,任务b又注册了一个微任务c,放入微任务队列中;
8.从微任务队列中取出任务c到主线程中,输出 also before timeout;微任务队列为空
9.从宏任务队列中取出任务到主线程,此任务中注册了一个微任务d,将其放入微任务队列中,接下来遇到输出4,宏任务队列为空
10.从微任务队列中取出任务d到主线程 ,输出test,微任务队列为空
案例3:
console.log('1'); // 同步 1
setTimeout(function() { // 异步宏任务
console.log('2'); // 同步 5
process.nextTick(function() { // 异步微任务 7
console.log('3');
})
new Promise(function(resolve) {// 同步 6
console.log('4');
resolve();
}).then(function() {// 异步微任务 8
console.log('5')
})
})
process.nextTick(function() { // 异步微任务 3
console.log('6');
})
new Promise(function(resolve) { // 同步 2
console.log('7');
resolve();
}).then(function() { // 异步微任务 4
console.log('8')
})
setTimeout(function() { // 异步宏任务
console.log('9'); // 同步 9
process.nextTick(function() {// 异步微任务11
console.log('10');
})
new Promise(function(resolve) {// 同步10
console.log('11');
resolve();
}).then(function() {// 异步微任务 12
console.log('12')
})
})
// 1 7 6 8 2 4 3 5 9 11 10 12