我爱编程

【译】Node事件循环

2018-05-17  本文已影响0人  Observer_____

第一次翻译文档,渣翻请见谅。
原文链接 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
参考链接 http://www.cnblogs.com/MuYunyun/p/7287413.html
http://www.cnblogs.com/MuYunyun/p/7287413.html

什么是事件循环?

事件循环是使Node.js得以执行非阻塞I/O操作的——即使JavaScript是单线程的,通过在任何可能的时候将操作offload到系统内核。

最现代的内核是多线程的,它们能处理多个操作在后台执行。当这些操作的其中之一完成,内核告诉Node.js,使得合适的callback可以被加入到poll队列中,最终被执行。

事件循环解释

当Node.js启动,它初始化事件循环,处理提供的输入脚本(或丢入REPL),这可能导致异步API调用,调度定时器,或者调用process.nextTick(),然后开始处理事件循环。

   ┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤ connections,┤      
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

每个阶段有一个callback的FIFO队列等待执行。一般来说,当事件循环进入到一个给定的阶段,它会执行这个阶段的所有具体的操作,然后执行这个阶段的队列中的callback,直到队列好近或callback 的最大数量被执行。之后事件循环会移动到下一个阶段。

阶段概览

阶段细节

timers

一个定时器指定阈值,一个提供的回调函数可能在这个threshold阈值之后,而不是我们想要它被执行的exact实际的时间被执行。定时器的回调函数会在它们被指派在指定长度的时间之后尽早执行;然而,操作系统调度或其他回调函数的运行可能会推迟它们。
注意:理论上,exact轮询阶段控制定时器何时被执行。
例如,你设置一个timeout在100ms的阈值吼执行,然后你的搅拌开始异步读取一个文件,读取文件花费95ms:

const fs = require('fs');

function someAsyncOperation(callback) {
  // Assume this takes 95ms to complete
  fs.readFile('/path/to/file', callback);
}

const timeoutScheduled = Date.now();

setTimeout(() => {
  const delay = Date.now() - timeoutScheduled;

  console.log(`${delay}ms have passed since I was scheduled`);
}, 100);


// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
  const startCallback = Date.now();

  // do something that will take 10ms...
  while (Date.now() - startCallback < 10) {
    // do nothing
  }
});

当事件循环进入poll轮询阶段,它有一个空的队列(fs.readFile()尚未完成),因此它会等待剩余的毫秒数直到达到最快定时器的阈值。当等待了95ms,fs.readFile()完成读取文件,它的花费10ms来完成的回调函数被加入到poll队列并被执行。当回调函数完成,队列中没有其他的回调函数了,于是事件循环会看最快定时器的阈值已经被达到,然后wrap back回到timers定时器阶段来执行定时器的回调函数。在这个例子中,你会看到定时器被设置和它的回调函数被执行的总延迟为105ms。

注意: 为了避免poll轮询阶段耗尽事件循环,libuv(实现Node.js事件循环和平台的所有异步行为的C库)也有一个hard最大值(系统依赖)来阻止对更多事件轮询。

pending callbacks

这个阶段为一些系统操作,如TCP错误类型,执行回调函数。例如,如果一个TCP套接字在尝试连接时接收到了ECONNREFUSED,一些系统想等待来报告这个错误。这回被放入pending callbacks的队列中来执行。

poll

poll轮询阶段有两个主要的功能:

  1. 计算它该阻塞多久和轮询I/O, 然后
  2. 处理poll队列中的事件。
    当事件循环进入poll阶段,且没有定时器被设置,两件事之一会发生:

一旦poll队列为空,事件循环会检查timers定时器,它们的时间阈值被达到。如果一个或多个定时器就绪,事件循环会回到timers阶段来执行那些定时器的回调函数。

check

这个阶段允许我们在poll阶段完成后立即执行回调函数。如果poll阶段变为闲置,且脚本被setImmediate()设置,事件循环会来到check阶段而不是等待。

setImmediate()实际是一个特殊的定时器,运行在事件循环的分开的阶段。它使用一个libuvAPI,这个API设置回调函数在poll阶段完成后来执行。

一般来说,在代码被执行时,事件循环最终会进入poll阶段,在这里它会等待一个到来的连接,请求,等等。然而,如果一个回调函数已经被setImmediate()设置且poll阶段变为闲置,它会终止并进入到check阶段而不是等待poll轮询事件。

close callbacks

如果一个socket或handle被突然关闭(e.g. socket.destroy()),这个'close'事件会在这个阶段被射出。否则它会通过process.nextTick()被射出。

setImmediate() VS setTimeout()
两者类似,但是根据被调用的时间会发生不同的行为。

定时器被执行的顺序会根据它们被调用时处在的上下文而变化。如果都在主模块中被调用,则timing会被进程的性能限制(进程的性能可能会被机器上运行的其他应用程序影响)。

例如,如果我们运行以下的不处于一个I/O cycle(也就是主模块)内部的脚本,这两个定时器被执行的顺序是不一定的,因为受到了进程性能的限制:

// timeout_vs_immediate.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate

$ node timeout_vs_immediate.js
immediate
timeout

然而,如果你把两个调用移动到一个I/O cycle里面,immediate 回调函数总是先执行:

// timeout_vs_immediate.js
const fs = require('fs');

fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout');
  }, 0);
  setImmediate(() => {
    console.log('immediate');
  });
});
$ node timeout_vs_immediate.js
immediate
timeout

$ node timeout_vs_immediate.js
immediate
timeout

使用setImmediate()而不是setTimeout()的主要优点是,当处在I/O cycle之内时,前者总是在任何其他定时器之前执行,不管当前有多少个定时器。

上一篇 下一篇

猜你喜欢

热点阅读