node的事宜机制

什么是事宜轮回(event loop)?

只管js是单线程的,事宜轮回机制,经由过程在适宜的时刻把操纵交给体系内核,从而许可node实行非壅塞的io操纵
当操纵完成时,内核示知node.js,适宜的回调函数会被到场轮询行列,终究被实行。
Node.js启动的时刻,初始化event loop,处置惩罚供应的剧本,剧本中能够挪用异步API,调理timers,或许挪用process.nextTick(),然后处置惩罚event loop

下图是简化的事宜轮回操纵递次图overview

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

图中每一个box就是一个phase,每一个phase有一个先进先出的回调函数的行列,
event loop进入了一个phase,就会实行phase中一切的操纵,然后实行回调函数,直到行列耗尽了,或许回调函数实行数目抵达最大数,接下来就去下一个phase

由于任何一个操纵都能够调理更多的操纵,而且poll phase中新的事宜由内核列队,所以正在轮询的事宜在被处置惩罚的时刻,poll事宜们能够会列队。
效果:长时候的运转回调函数许可poll phase运转事宜比timer的阈值更长。

phase overview 阶段概略

  • timers:实行由setTimeout() and setInterval()调理的回调函数

  • I/O callbacks:实行一切的回调函数,除了 close callbacks(由timers,setImmediate()调理)

  • idle, prepare:内部运用

  • poll:猎取新的io事宜,当适宜的时刻,node会壅塞在这里

  • check: setImmediate()回调函数会在这里挪用

  • close callbacks: e.g. socket.on(‘close’, …)

每次运转event loop,node搜检是不是有对任何异步io或许timers的守候,没有就封闭

Phases in Detail(各阶段细述)

timers

timers指定阈值(threshold)今后,会实行回调函数,但threshold不是实行回调函数的确实时候(只是最短时候)。
timers回调函数一旦能够实行了就会被实行。但是操纵体系的调理或许其他的回调函数能够推延它的实行。
由poll phase来掌握什么时刻timers被实行

var fs = require('fs');
function someAsyncOperation (callback) {
  // Assume this takes 95ms to complete
  fs.readFile('/path/to/file', callback);
}
var timeoutScheduled = Date.now();
setTimeout(function () {
  var delay = Date.now() - timeoutScheduled;
  console.log(delay + "ms have passed since I was scheduled");
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(function () {
  var startCallback = Date.now();
  // do something that will take 10ms...
  while (Date.now() - startCallback < 10) {
    ; // do nothing
  }
});

一开始timer被调理,内里的回调函数实行log。
然后事宜轮回进入poll phase,此时行列是空的(由于fs.readFile()没有完成),所以就会等着,直到最早的timer的阈值(100)到时候,等了95 ms(还没到,毕竟定的是100),fs.readFile() 这个时刻完成了,所以它的回调函数就回被加poll的行列而且被实行(实行10s),当回调函数完成了,行列又空了,所以,event loop将会看到timer的阈值(100)已到了,
然后回到timers这个phase去实行timers的回调函数,也就是,打印出105秒

为了防备poll phase 独有耗尽 event loop,libuv 也有一个最大值(基于体系),会在凌驾最大值之前住手轮询更多的事宜。

I/O callbacks

为体系操纵(比方tcp毛病范例)实行回调函数
当tcp socket尝试衔接时接收到ECONNREFUSED,类unix体系将会想报导毛病,要会在这个phase列队实行。

poll

poll phase有两个功用

  • 为到了时候的timers实行剧本,然后

  • 处置惩罚poll行列的事宜

当event loop 进入poll phase且没有timers被调理,下面的事变会发作

  • poll不空,

    • 经由过程回调函数行列迭代的实行

  • poll栈是空的

    • 假如剧本已被setImmediate()调理,事宜轮回将会停止poll phase,到check phase去实行那些被调理的剧本

    • 等着回调函数被加进行列,然后立马实行它
      一旦poll空了,event loop将回搜检timers有无thresholds到了,有的话,wrap back to the timers phase,然后实行timers的回调函数

check

迥殊的 timer

close callbacks

setImmediate and setTimeout()

  • 在poll完成今后实行

  • 在最小事宜今后实行

实行递次:
依赖于挪用的上下文

  • 假如都在main module ,事宜会被历程的机能限定(被其他运用影响)

    • not within an I/O cycle:不确定的

    • within an I/O cycle:immediate老是先(更好)

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

setImmediate(function immediate () {
  console.log('immediate');
});
// timeout_vs_immediate.js
var fs = require('fs')

fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  setImmediate(() => {
    console.log('immediate')
  })
})

The Node.js Event Loop, Timers

参考:

    原文作者:小帆
    原文地址: https://segmentfault.com/a/1190000008473830
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞