宏任务和微任务:setTimeout和Promise执行顺序

6,731 阅读1分钟

先来一个经典的题

    setTimeout(function () {
      console.log(1);
    }, 0);
    new Promise(function (a, b) {
      console.log(2);
      for (var i = 0; i < 10; i++) {
        if (i == 9) a()
      }
      console.log(3)
    }).then(function () {
      console.log(4)
    });
    console.log(5);
        function a() {
      console.log(3)
    }
正确输出顺序为:2,3,5,4,1;

        这里就要提到js的事件循环了,js是单线程的缺可以处理异步,就是因为Event Loop(事件循环)。

       任务进入执行栈,会先判断是同步还是异步任务,同步任务会被加入主线程继续执行,而异步任务会被挂起,当异步任务有返回值时会被添加到事件队列,当主线程闲置时,主线程会去查找事件队列是否有任务,将排在第一位事件的回调放入执行栈,执行同步代码,如此反复,这个过程就被成为 事件循环。


  • macro-task(宏任务):script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

   js的异步执行机制是这样的,不同类型的任务会进入不同的Event Queue,有宏任务的队列和微任务的队列。代码开始执行时,先执行宏任务,接着执行所有微任务,然后再执行宏任务....

  


然后我们再来看这段代码。
  1. 运行到 settimeout,将其回调函数添加到宏任务;
  2. 运行到new promise,立即执行输出 ‘ 2 ’,执行for循环,进入if判断,执行a函数输出  '3'  then回调添加到微任务;
  3. 运行到console,输出‘5’;
  4. 宏任务结束,检查微任务,发现then回调,输出‘4’
  5. 第二轮开始,发现宏任务settimeout的回调,输出‘1’
  6. 结束