首页 > Web开发 > 详细

js中的宏任务与微任务

时间:2019-12-09 11:12:30      阅读:49      评论:0      收藏:0      [点我收藏+]

如果你已经知道了js中存在宏任务和微任务,那么你一定已经了解过promise了。因为在js中promise是微任务的一个入口。
先来看一道题:

setTimeout(function(){
    console.log('setTimeout')
});

new Promise(function(resolve, reject){
    console.log('pormise body');
    resolve();
}).then(function(){
    console.log('promise then')
});

console.log('main');

这题的答案是:

promise body
main
promise then
setTimeout

promise body出现在第一行一点也不意外,意外的是,setTimeout出现在了promise then的后边。
?
setTimeout和promise then都是异步调用,setTimeout又定义在promise之前,如果没有意外,应该是先输出setTimeout才对,但这里却恰恰相反。
?
这里涉及到的知识点,就是宏任务与微任务了。标记一下上边的代码:

setTimeout(function(){ // 同步代码,语句1
    console.log('setTimeout') // 宏任务,语句2
});

new Promise(function(resolve, reject){
    console.log('pormise body'); // 同步代码,语句3
    resolve(); // 同步代码,语句4
}).then(function(){
    console.log('promise then') // 微任务,语句5
});

console.log('main'); // 同步代码,语句6

那么他们运行的规则是怎样的呢?
?
原来,宏任务与微任务,都各自有一个调用队列(先进先出)。
?
遇到宏任务,微任务,则将他们推入各自的调用队列。需要注意的是,同步代码也是宏任务。
?
宏任务执行完一个,则去清空微任务队列,微任务清空后再去执行下一个宏任务。
?
我们来把上面的代码一行一行解读一下:
?
首先定义两个队列,宏任务队列:MacroQqueue, 微任务队列: MicroQueue
?
第一步,先按同步代码顺序运行
同步代码,语句1: 添加一个宏任务,将语句2推入MacroQueue。 // MacroQueue: [{task: 语句2}]
同步代码,语句3: 打印promise body
同步代码,语句4: 添加一个微任务,将语句5推入MicroQueue。 // MicroQueue: [{task: 语句5}]
同步代码,语句6: 打印main。 // 同步代码(宏任务)完成
?
第二步,开始清空微任务队列
微任务: 语句5,从MicroQueue跳出,打印promise then。 // 微任务队列全部清空
?
第三步,开始清空宏任务队列
宏任务:语句2,从MacroQqueue跳出,打印setTimeout // 宏任务队列全部清空
?
第四步:开始清空微任务队列
队列为空...
?
一轮循环完成。开始下一轮,如此循环下去。
?
通过上面的讲解,大家应该能对宏任务,微任务的运行机制有了一定的了解了吧。那么都有哪些常见的宏任务与微任务呢?
请看下表:
?

宏任务 浏览器 nodejs
同步代码 ? ?
I/O ? ?
setTimeout ? ?
setInterval ? ?
setImmediate ? ?
requestAnimationFrame ? ?

?

微任务 浏览器 nodejs
process.nextTick ? ?
MutationObserver ? ?
Promise (async/await) ? ?

好了,我们来一道复杂一点的题练练手:

console.log('sync statement 1');
Promise.resolve().then(function() {
    console.log('micro task 1');
    setTimeout(function() {
        console.log('macro task 1');
    }, 0);
}).then(function() {
    console.log('micro task 2');
});

setTimeout(function() {
    console.log('macro task 2')
    Promise.resolve().then(function(){
        console.log('micro task 3');
    })
}, 0)
console.log('sync statement 2');

//输出:
// sync statement 1
// sync statement 2
// micro task 1
// micro task 2
// macro task 2
// micro task 3
// macro task 1

标注一下方便大家分析:

console.log('sync statement 1'); // 同步代码,语句1
Promise.resolve().then(function() { // 同步代码,语句2,注册了一个微任务
    console.log('micro task 1'); // 微任务,语句3
    setTimeout(function() { // 微任务,语句4,同时注册了一个宏任务
        console.log('macro task 1'); // 宏任务,语句5
    }, 0);
}).then(function() {
    console.log('micro task 2'); // 微任务,语句6
});

setTimeout(function() { // 同步代码,语句7
    console.log('macro task 2') // 宏任务,语句8
    Promise.resolve().then(function(){ // 宏任务,语句9,同时注册了一个微任务
        console.log('micro task 3'); // 微任务,语句10
    })
}, 0)
console.log('sync statement 2'); // 同步代码,语句11

js中的宏任务与微任务

原文:https://www.cnblogs.com/yinzhida/p/12009738.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!