宏任务和微任务

宏任务和微任务

        微任务 --- microtask称为jobs, 宏任务 --- macrotask称为task,  宏任务是由宿主发起的,而微任务由JavaScript自身发起。

常见的面试题

console.log('start')

setTimeout(()=>{
   console.log('setTimeout')
},0)

new Promise((resolve)=>{
   console.log("promise");
   resolve();
}).then(()=>{
   console.log("then1");
}).then(()=>{
   console.log("then2");
})

console.log("end");

它的顺序是

start 
promise
end
then1
then2
setTimeout

  

实践

  解:

  Event Loop中,每一次循环称为tick,每一次tick的任务如下:

  执行栈选择最先进入队列的宏任务,执行其同步代码直至结束;

  检查是否存在微任务,有则会执行微任务队列为空;

  如果宿主为浏览器,可能会渲染页面;

  开始下一轮tick,执行宏任务中的异步代码;

  setImmediate 和 process.nextTick 为Node环境下常用的方法,所以基于Node宿主分析。

  ( Node.js是运行在服务端的js,虽然用到也是v8引擎,但由于服务目的和环境不同,导致了它的API和原生JS有些区别,其EventLoop还要处理一些I/O,比如新的网络连接等。)

  执行顺序如下:

     1、timers: 执行setTimeout和setInterval的回调。

     2、pending callbacks:执行延迟到下一个循环迭代的I/O回调。

     3、idle prepare:仅系统内部使用。

     4、poll:检索新的I/O事件;执行与I/O事件相关的回调。

     5、check: setImmediate在这里执行。

     6、close callbacks: 一些关闭的函调函数

 setImmediate和setTimeout

console.log("outer");
setTimeout(() => {
     setTimeout(() => {
        console.log("setTimeout");
     },0);

     setImmediate(() => {
        console.log("setImmediate")
      })
},0)

  其执行顺序为:

   1、外层是一个setTimeout,所以执行它的回调函数已经在timers阶段了。

   2、处理里边的setTimeout,因为本次循环的timers正在执行,所以其回调其实加到了下一级timers阶段

   3、处理里边的setImmediate,将它的回调加入check阶段的队列。

   4、外层timers阶段处理完,进入pending callbacks,idle,prepare,poll,这几个队列都是空的,所以继续住下到了check阶段,发现了setImmediate的回调,拿出来执行

   5、然后是close callbacks,队列是空的,跳过

     

  在Node里边对setTimeout的特殊处理,setTimeout(fn, 0)会被强制改为setTimeout(fn, 1)

      1、遇到setTimeout,虽然设置的是0毫秒触发,但是被node.js强制改为1毫秒,塞入timers阶段。

      2、遇到setImmediate塞入check阶段。

      3、同步代码执行完毕,进入Event  Loop

      4、先进入timers阶段,检查当前时间过去了1毫秒没有,如果过了1毫秒,满足setTimeout条件,执行回调,如果没过14毫秒,跳过。

      5、跳过空的阶段,进入check阶段,执行setImmediate

     可见,1毫秒是个关键点,所以,setImmediate不一定在setTimeout之前执行了。

   promise 和 process.nextTick

   因为 process.nextTick 为node环境下的方法,是一个特殊的异步API,其不属于任何的Event Loop阶段。

   事实上Node在遇到这个API时,Event Loop根本不会继续进行,会马上停下来执行process.nextTick( ), 这个执行完才会继续Event Loop。所以,nextTick 和 Promise 同时出现,肯定是nextTick先执行,原因是nextTick的队列比Promise队列优先级更高。

   vue实例的nextTick( )方法接受一个回调函数作为参数,用于将回调延迟到下次DOM更新周期之后执行。这个API就是基于事件循环实现的。下次DOM更新就是下次微任务执行时更新DOM,而vm.$nextTick就是将回调函数添加到微任务中。

未完,待续......
原文地址:https://www.cnblogs.com/zhishiyv/p/14626630.html