js中的异步任务:宏任务、微任务
2020-01-17 本文已影响0人
jadefan
js的异步任务分2类:宏任务(macrotask )和微任务(microtask )
什么是宏任务、微任务
网上用食堂排队打饭或者银行排队办业务举例,个人认为不太恰当,他们并不是包含或嵌套关系。
js是单线程脚本语言,在需要执行异步任务时,就需要浏览器协助完成,形成一套事件循环机制(event loop)。
浏览器在完成js交给的异步任务后,会在js的回调队列中插入一个任务,等待js的同步任务执行完成后调用执行,比如计时器、网络请求等等,
虽说异步任务都放在等待队列中,但还是有区别的,分宏任务和微任务(猜测按优先级划分?),js在调用时,优先取出微任务,并且在执行过程中如果创建了新的作业,则放在本次执行完后紧接着调用,微任务执行完成后,再取出宏任务执行。
我也来举个栗子:
你们几个人去饭店吃饭,点餐后你们要先开一局王者荣耀,打到一半有个人要上厕所,但一致要他打完这局才能去;打完后菜已上齐但他要先去厕所,剩下的人就要等他回来后才能开饭。
(上厕所就是微任务,很急,吃饭就是宏任务,等紧急事情办法才能开始,整个过程就是一次事件循环)
宏任务、微任务有哪些
宏任务包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
微任务包括: Promises, Object.observe, MutationObserver
宏任务、微任务的执行顺序
- 先执行同步代码,
- 遇到异步宏任务则将异步宏任务放入宏任务队列中,
- 遇到异步微任务则将异步微任务放入微任务队列中,
- 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
- 微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
- 一直循环直至所有任务执行完毕。
实例1
setTimeout(function(){
console.log('1');
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3');
});
console.log('4');
- 遇到setTimout,异步宏任务,放入宏任务队列中;
- 遇到new Promise,Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2;
- 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
- 遇到同步任务console.log(‘4’);输出4;主线程中同步任务执行完
- 从微任务队列中取出任务到主线程中,输出3,微任务队列为空
- 从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空,结束~
输出:2 4 3 1
实例2
setTimeout(()=>{
new Promise(resolve =>{
resolve();
}).then(()=>{
console.log('test');
});
console.log(4);
});
new Promise(resolve => {
resolve();
console.log(1)
}).then( () => {
console.log(3);
Promise.resolve().then(() => {
console.log('before timeout');
}).then(() => {
Promise.resolve().then(() => {
console.log('also before timeout')
})
})
})
console.log(2);
- 遇到setTimeout,异步宏任务,将() => {console.log(4)}放入宏任务队列中;
- 遇到new Promise,Promise在实例化的过程中所执行的代码都是同步进行的,所以输出1;
- 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
- 遇到同步任务console.log(2),输出2;主线程中同步任务执行完
- 从微任务队列中取出任务到主线程中,输出3,此微任务中又有微任务,Promise.resolve().then(微任务a).then(微任务b),将其依次放入微任务队列中;
- 从微任务队列中取出任务a到主线程中,输出 before timeout;
- 从微任务队列中取出任务b到主线程中,任务b又注册了一个微任务c,放入微任务队列中;
- 从微任务队列中取出任务c到主线程中,输出 also before timeout;微任务队列为空
- 从宏任务队列中取出任务到主线程,此任务中注册了一个微任务d,将其放入微任务队列中,接下来遇到输出4,宏任务队列为空
- 从微任务队列中取出任务d到主线程 ,输出test,微任务队列为空,结束~
输出:1 2 3 before timeout also before timeout 4 test