美文网首页
宏任务和微任务

宏任务和微任务

作者: RadishHuang | 来源:发表于2021-06-28 15:28 被阅读0次

    浏览器是多线程执行代码,渲染的。但是浏览器只给JS一个线程来执行,因此JS是单线程。因此代码都是同步执行的,但是JS也有异步的任务,比如settimeout,async,await。这些都是异步的任务。因此引出宏任务和微任务,这两个都是异步任务。

    • 直接看经典的面试题
    async  function  async1 ()  {
        console.log('async1 start');
        await  async2();
        console.log('async1 end')
    }
    async  function  async2 ()  {
        console.log('async2')
    }
    console.log('script start');
    setTimeout(function ()  {
        console.log('setTimeout')
    },  0);
    async1();
    new  Promise(function (resolve)  {
        console.log('promise1');
        resolve()
    }).then(function ()  {
        console.log('promise2')
    });
    console.log('script end')
    
    • 先看主线程执行,按照代码,从上到下执行。
    • 遇到async1的函数,JS创建堆内存。但是没执行函数。继续执行
    • 遇到async2的函数,JS创建堆内存。但是没执行函数。继续执行
    • 遇到有输出,先输出。console.log('script start');。继续执行
    • 遇到settimeout,往宏任务添加console.log('setTimeout')的宏任务。继续执行
    • 遇到执行async1();找到这个函数的堆内存,执行函数。继续执行
    • async1的函数第一步打印出了 console.log('async1 start');。继续执行。
    • 执行 async2的函数console.log('async2');。添加微任务console.log('async1 end');
    • new Promise,是立即执行函数,执行了console.log('promise1');。添加微任务.then的方法console.log('promise2');
    • 输出console.log('script end')
    • 开始evenloop查找微任务。
    • 第一个微任务console.log('async1 end')
    • 第二个微任务console.log('promise2')
    • 微任务执行完毕,开始执行宏任务。console.log('setTimeout')
    执行流程
    • 整个逻辑就是,从上到下依次执行。如果遇到同步执行的,就直接执行。遇到宏任务,就添加到宏任务队列,遇到微任务,就添加到微任务队列。同步的执行完毕后,通过evenloop去取微任务,微任务取完毕后,才开始取宏任务。


      流程图

    第二道示范代码,注意宏任务跟微任务都要执行的时候,微任务优先。

    setTimeout(() => {
      console.log("time1");
      setTimeout(() => {
        console.log("time3");
      }, 0);
      new Promise((resolve) => {
        resolve();
        console.log("new resolve");
      }).then(() => {
        console.log("Promise then");
      });
    }, 0);
    setTimeout(() => {
      console.log("time2");
    }, 0);
    console.log("mian");
    
    • 代码从上到下执行。
    • 遇到setTimeout,把里面的代码块console.log("time1");等等之类的,丢到宏任务。
    • 遇到setTimeout,把console.log("time2");丢到宏任务。
    • console.log("mian"); 主线程执行完毕。
    • 开始执行第一个宏任务。console.log("time1");
    • 遇到setTimeout,把console.log("time3");丢到宏任务。
    • 遇到new Promise,直接执行。console.log("new resolve");。并且把.then后面的console.log("Promise then");扔到微任务。
    • 主线程执行完毕。
    • 这个时候有微任务和console.log("time2");的宏任务。按照优先级,执行微任务。因此先console.log("Promise then");
    • 微任务都执行完毕,取宏任务。console.log("time2");
    • 在再次查找,微任务没有,剩下最后一个宏任务。console.log("time3");

    留下题目

    
    
    console.log('==== start ====')
    setTimeout(function () {
      console.log('定时器')
      setTimeout(function () {
        console.log('定时器中的定时器')
      }, 0)
      new Promise(function (resolve) {
        console.log('准备执行 for 循环111')
        for (let i = 0; i < 666; i++) {
          i == 5 && resolve()
        }
      }).then(function () {
        console.log('执行了 then 方法1111')
      })
    
    }, 0)
    console.log('==== end ====')
    new Promise(function (resolve) {
      console.log('准备执行 for 循环222')
      for (let i = 0; i < 666; i++) {
        i == 5 && resolve()
      }
    }).then(function () {
      console.log('执行了 then 方法2222')
    })
    
    

    不能被resolve混淆了。先执行first()。然后才是then进入微任务。因此first()方法里面的p.then微任务更先进。

    
    
    const first = () => (
      new Promise((resolve, reject) => {
        console.log(3);
        resolve(2);
        let p = new Promise((resolve, reject) => {
          console.log(7);
          setTimeout(()=>{
            console.log(5);
            resolve(6);
          }, 0)
          resolve(1);
        })
        p.then((arg) => {
          console.log(arg);
        })
      })
    )
    
    first().then((arg)=>{
      console.log(arg);
    })
    console.log(4);
    

    相关文章

      网友评论

          本文标题:宏任务和微任务

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