• 定时器setTimeout()和Node.js的Event Loop


    一、定时器

      setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"尾部添加一个事件,因此要等到同步任务"任务队列"现有的事件都处理完,才会得到执行。

      需要注意的是,setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

    二、Node.js的Event Loop

      Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。

      除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与"任务队列"有关的方法:process.nextTicksetImmediate。它们可以帮助我们加深对"任务队列"的理解。

      process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。请看下面的例子(via StackOverflow)。

      如果有多个process.nextTick语句(不管它们是否嵌套),将全部在当前"执行栈"执行。

      process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句总是在当前"执行栈"一次执行完,多个setImmediate可能则需要多次loop才能执行完。事实上,这正是Node.js 10.0版添加setImmediate方法的原因,否则像下面这样的递归调用process.nextTick,将会没完没了,主线程根本不会去读取"事件队列"!

      另外,由于process.nextTick指定的回调函数是在本次"事件循环"触发,而setImmediate指定的是在下次"事件循环"触发,所以很显然,前者总是比后者发生得早,而且执行效率也高(因为不用检查"任务队列")。

     

     三、Macrotasks和Microtasks

    Macrotasks和Microtasks 都属于上述的异步任务中的一种,他们分别有如下API:
    macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
    microtasks: process.nextTick, Promise, MutationObserver

    setTimeout的macrotask, 和 Promise的microtask 有哪些不同,先来看下代码如下:

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

       

      如上代码可以看到,Promise的函数代码的异步任务会优先setTimeout的延时为0的任务先执行。

      原因是任务队列分为 macrotasks 和 microtasks, 而promise中的then方法的函数会被推入到microtasks队列中,而setTimeout函数会被推入到macrotasks任务队列中,在每一次事件循环中,macrotask只会提取一个执行,而microtask一直提取,直到microsoft队列为空为止。

      也就是说如果某个microtask任务被推入到执行中,那么当主线程任务执行完成后,会循环调用该队列任务中的下一个任务来执行,直到该任务队列到最后一个任务为止。

      而事件循环每次只会入栈一个macrotask,主线程执行完成该任务后又会检查microtasks队列并完成里面的所有任务后再执行macrotask的任务。

     

  • 相关阅读:
    工程思维
    小骆驼 第三章 列表与数组
    小骆驼 第二章 标量数据
    小骆驼 第二章 标量数据
    小骆驼 第二章 标量数据
    split和join合写
    Competition and Predation
    What is the difference between Θ(n) and O(n)?
    数学基础之概率统计
    enumerate()函数
  • 原文地址:https://www.cnblogs.com/lulin1/p/9703008.html
Copyright © 2020-2023  润新知