美文网首页
Event Loop、macrotask、micritask的结

Event Loop、macrotask、micritask的结

作者: tangyefei | 来源:发表于2020-01-14 18:28 被阅读0次

    参考资料

    Event Loop

    JavaScript是单线程的语言,为了处理一些耗时的任务,会将任务分布到主线程和任务队列中。

    一旦主线程的所有任务执行完毕,就会读取任务队列里面的任务。

    macrotask vs microtask

    任务队列里的任务又分macrotask和microtask,并且单独维护。

    如果你需要在同步中进行异步任务,那么使用microtask;否则就使用macrotask。

    • macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

    • microtasks: process.nextTick, Promises, Object.observe, MutationObserver

    执行顺序

    1. 执行主线程的任务
    2. 遇到一些非立即执行的任务,分别放到macrotask和microtask队列中。
    3. 立即执行microtask中所有的任务。
    4. 开始执行macrotask中的第一个任务,并且可能继续产生新的任务。
    5. 如果4产生了microtask,会继续执行3。
    6. 接着4开始执行下一个macrotask任务。

    执行示例

    例子1 then.then

    考察了then.then的执行是有依赖顺序的

    new Promise((resolve,reject)=>{
      console.log("1")
      resolve()
    }).then(()=>{
      console.log("2")
    }).then(()=>{
      console.log("3")
    })
    // 1,2,3
    
     new Promise((resolve,reject)=>{
      console.log("1")
      resolve()
    }).then(()=>{
      console.log("2")
      return new Promise((resolve,reject)=>{
        console.log("3")
        resolve()
      }).then(()=>{
        console.log("4")
      }).then(()=>{
        console.log("5")
      })
    
    }).then(()=>{
      console.log("6")
    })
    // 1,2,3,4,5,6
    

    例子2 then.then + then

    主要考察了then.then会被当做the.then,被插入到micro队列的末尾,从而最后执行:

    Promise.resolve().then(()=>{
        console.log(1);
    }).then(()=>{
        console.log(2);
    });
    Promise.resolve().then(()=>{
        console.log(3);
    })
    // 1,3,2
    
    console.log('begin');
    setTimeout(() => {
        console.log('setTimeout 1');
        Promise.resolve()
            .then(() => {
                console.log('promise 1');
                setTimeout(() => {
                    console.log('setTimeout2');
                });
            })
            .then(() => {
                console.log('promise 2');
            });
        new Promise(resolve => {
            console.log('a');
            resolve();
        }).then(() => {
            console.log('b');
        });
    }, 0);
    console.log('end');
    
    // begin, end, setTimeout 1, a, promise 1, b, promise 2, setTimeout2,
    

    例子3 macro.micro > macro

    考察了第一个setTimeout执行时,生成了micro(输出7),这时候可以插队到第二个setTimeout(输出3)前。

    console.log(1);
    
    setTimeout(() => {
      console.log(2);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      })
    })
    
    setTimeout(() => {
      console.log(3);
    })
    
    new Promise((resolve)=>{
      console.log(4);
      resolve();
    }).then(()=>{
      console.log(5);
    })
    // 1,4,5,2,6,7,3
    

    同样一个插队的例子。

    console.log(1);
    
    setTimeout(() => {
      console.log(2);
    })
    
    setTimeout(() => {
      console.log(3);
    })
    
    new Promise((resolve)=>{
      console.log(4);
      resolve();
    }).then(()=>{
      console.log(5);
    })
    
    // 1 4 5 2 3
    

    各种不讲理插队的例子。

    console.log(1);
    
    setTimeout(() => {
      console.log(2);
    })
    
    setTimeout(() => {
      console.log(3);
    })
    
    new Promise((resolve)=>{
      console.log(4);
      resolve();
    }).then(()=>{
      console.log(5);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      })
    })
    // 1 4 5 6 7 2 3 
    

    变着法插队的例子。

    console.log(1);
    setTimeout(() => {
      console.log(2);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      })
    })
    
    setTimeout(() => {
      console.log(3);
    })
    
    new Promise((resolve)=>{
      console.log(4);
      resolve();
    }).then(()=>{
      console.log(5);
    })
    // 1 4 5 2 6 7 3
    

    例子4 node.js下的执行

    在浏览器环境应该输出1 2 3 4,实际在node.js下是1 2 4 3,可见micro不插队,要等macro都走一遍。

    setTimeout(function() {
        console.log(1);
        new Promise(function(resolve) {
            console.log(2);
            resolve();
        }).then(function() {
            console.log(3)
        })
    });
    setTimeout(function() {
        console.log(4);
    });
    // 1 2 4 4 
    

    尽管如此,对于如下为什么5不是在10面前,仍旧是不理解?

    console.log('1');
    
    setTimeout(function() {
        console.log('2');
        process.nextTick(function() {
            console.log('3');
        })
        new Promise(function(resolve) {
            console.log('4');
            resolve();
        }).then(function() {
            console.log('5')
        })
    })
    process.nextTick(function() {
        console.log('6');
    })
    new Promise(function(resolve) {
        console.log('7');
        resolve();
    }).then(function() {
        console.log('8')
    })
    
    setTimeout(function() {
        console.log('9');
        process.nextTick(function() {
            console.log('10');
        })
        new Promise(function(resolve) {
            console.log('11');
            resolve();
        }).then(function() {
            console.log('12')
        })
    })
    
    // 7 6 8 2 4 9 11 3 10 5 12 
    

    相关文章

      网友评论

          本文标题:Event Loop、macrotask、micritask的结

          本文链接:https://www.haomeiwen.com/subject/crbaactx.html