renmm / blogs

整理自己平时遇到的技术wiki
1 stars 0 forks source link

理解宏任务和微任务 #37

Open renmm opened 3 years ago

renmm commented 3 years ago

event loop

以一个宏任务(script(整体代码))开始,内部执行task,执行完当前所有的微任务队列后,单个宏任务完毕,返回值。 可以简单理解为2层循环,外层为宏任务循环,内存为微任务循环。

event loop

特点:

执行下看看,会输出啥

(function test() {
    setTimeout(function() { console.log(1) }, 0); //回调会被添加到macro-task队列
    new Promise(function(resolve) {
        console.log(2);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(3);
    }).then(function() { // then 1
        console.log(4);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(5);
            }, 0);
            console.log(6);
        }).then(function() { // then 2
            console.log(7); //回调会在resolve后,添加到micro-task队列
        });
    }).then(function() { // then 3
        console.log(10);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(11);
            }, 0);
            console.log(12);
        }).then(function() { // then 4
            console.log(13); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(8);
    return 9;
})();
//控制台打印的结果如下:
//2
//3
//8
//4
//6
//10
//12
//9 (此次是chrome输出的,干扰项,请忽略,因为多个语句块,也只返回最后一个,所以没有任何意义~)
//1
//5
//7
//11
//13

分析:

从script开始(整体代码):

第一轮:

入栈: task = [ 2, 3, 8, ]

console: 2,3,8,

简化宏任务,实际是发起异步任务,异步任务执行完毕,再将cb存放到macro-task

macro-task = [ 1, ] micro-task = [ then 1 ]

执行micro-task: then 1 入栈: task = [4, 6] console: 4,6 macro-task = [ setTimeout(1), setTimeout(5) ] micro-task = [ then 3 ]

执行micro-task:then 3 入栈: task = [10, 12] macro-task = [ setTimeout(1), setTimeout(5), setTimeout(11) ]

setTimeout(1) 直接执行,没啥可说的 ... 执行macro-task: setTimeout(5) 入栈: task = [5] micro-task = [then 2]

最终console: 2,3,8,4,6,10,12 1, 5,7 11,13

能理解下面的,基本没问题了

let a = (function test() {
    setTimeout(function() { console.log(1) }, 0); //回调会被添加到macro-task队列
    new Promise(function(resolve) {
        console.log(2);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(3);
    }).then(function() { // then 1
        console.log(4);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(5);
            }, 0);
            console.log(6);
        }).then(function() { // then 2
            console.log(7); //回调会在resolve后,添加到micro-task队列
        });
    }).then(function() { // then 3
        console.log(10);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(11);
            }, 0);
            console.log(12);
        }).then(function() { // then 4
            console.log(13); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(8);
    return 9;
})();
console.log(a)
console.log(77);

let b = (function test2 () {
    setTimeout(function() { console.log(21) }, 0);
    new Promise(function(resolve) {
        console.log(22);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(23);
    }).then(function() { // then 1
        console.log(24);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(25);
            }, 0);
            console.log(26);
        }).then(function() { // then 2
            console.log(27); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(88);
    return 99;
})();

console.log(b)

//控制台打印的结果如下:
//2
//3
//8
//9
//77
//22
//23
//88
//99
//4
//6
//24
//26
//10
//12
//1
//21
//5
//7
//25
//27
//11
//13 

参考 https://zhuanlan.zhihu.com/p/30894022 (图)