2、Node的异步I/O请求对象

2019-07-26  本文已影响0人  萘小蒽

对于一般的(非异步)回调函数,函数由我们自行调用:

var froEach = function (list, callback) {
  for (let i = 0; i < list.length; i++) {
    callback(list[i], i, list)
  }
}

而对于Node中的异步I/O调用而言,回调函数却不由开发者来调用。

我们从发出调用异步后,到回调被执行,中间发生了什么呢?
从JavaScript发出调用异步,到内核执行异步I/O操作的过渡过程中,存在一种中间产物,它叫做请求对象

以简单的fs.open()方法来作为例子:

fs.open = function (path, flags, mode, callback) {
  // ...
  binding.open(pathModule._makeLong(path), stringToFlags(flags), mode, callback);
};

fs.open()的作用是根据指定路径和参数去打开一个文件,从而得到一个文件描述符,这是后续I/O的初始操作

fs.open()调用示意图
  1. JavaScript调用node的核心模块,核心模块调用C++内建模块,内建模块通过libuv进行系统调用,这是node里经典的调用方法。
  2. 上面图中libuv作为封装层,有两个平台的实现,实质上是调用了uv_fs_open()方法。
  3. uv_fs_open()的调用过程中,创建了一个FSReqWrap请求对象。从JavaScript层传入的参数和当前方法都被封装在这个请求对象中。
  4. 最为关注的回调函数则被设置在这个FSReqWrap请求对象的oncomplete_sym属性上。

请求对象是异步I/O过程中重要中间产物,所有的状态都保存在这个对象中,包括送入线程池等待执行以及I/O操作完毕后的回调处理。

对象包装完毕后,在windows下,则调用queueUserWorkitm()方法将这个FSReqWrap请求对象推入线程池中等待执行。

至此,JavaScript调用立即返回,由JavaScript层面发起的异步调用的第一阶段就此结束。JavaScript线程可以继续执行当前任务的后续操作。当前的I/O操作在线程池中等待执行,不管它是否阻塞I/O,都不会影响到JavaScript线程的后续执行,达到了异步的目的。

上一篇 下一篇

猜你喜欢

热点阅读