Node.js执行程序需要哪些步骤?

时间:2014-04-03 19:41:02

标签: node.js

我正在探索node.js很长一段时间了。但还没有弄清楚程序是如何执行的。

例如采取这个简单的程序:

// file app.js`

var fs = require('fs');

var fileBuffer = fs.readFileSync('./sample.txt');

fs.readFile('./resource.json', function (er, data) {    
    console.log(data);
});

console.log(fileBuffer);

现在,当我们输入node app.js(在命令行上)时,幕后会发生什么,直到程序结束。

具体来说,我想了解:

  1. 事件循环如何处理前两个阻塞I / O调用,以及;
  2. 关注异步。功能,一旦I / O完成,它发送到事件队列的内容以及如何&当附加的回调被调用时。

2 个答案:

答案 0 :(得分:4)

阻止I / O只是:在完成之前调用不会返回。因此,当您调用readFileSync时,它会直接调用OS API来读取文件,并且只有在将整个内容复制到Buffer时才会控制返回到您的JS。

使用阻塞(同步)函数,事件循环与I / O的处理方式完全无关。这就是为什么同步I / O在节点中非常糟糕 - 它会阻止其他任何事情发生,因为事件循环没有运行。

另一方面,像readFile这样的普通(异步)I / O函数只是放入I / O请求,然后返回。具体如何执行I / O取决于I / O请求的性质(即文件系统或网络),但它全部由C库libuv在单独的线程上处理。

  • 网络I / O实际上是使用主机操作系统的原生asynchronous I/O facilities执行的,非常快不需要为每个连接使用单独的线程。

    每当操作系统报告网络I / O活动时,事件就会被放入队列中。在事件循环的下一个标记处,事件被拾取并分派到适当的JavaScript函数。 (C代码可以获取对JS函数的引用并调用它们。)

  • 使用常规阻塞系统I / O调用完成文件I / O.每个I / O请求都放在libuv work queue中并由线程池执行。这里的关键是阻塞I / O在C语言中完成,位于与JavaScript线程分开的线程上。

    当阻塞I / O调用返回时,结果将放入队列中。同样,该事件将在下一个时间点发送。

Node保留待处理工作请求的引用计数 - 例如I / O,计时器和侦听服务器。如果在勾选结束时归零,则该过程退出。 (在某些情况下,您可以使用unref()从引用计数中明确删除活动请求。)

其他一些相关答案将有助于进一步解释其中的一些概念:


最后,让我们来看看你的示例程序。这里到底发生了什么:

  • require('fs')为您提供已初始化的fs模块的参考。内置模块很特殊,不需要加载I / O.
  • fs.readFileSync调用操作系统文件API。在将文件内容复制到内存之前,它不会返回。
  • fs.readFile将一个项目(包含文件名和对回调的引用)添加到libuv工作队列,然后立即返回。 (因为工作队列中没有任何内容,I / O将很快在一个单独的线程上开始。)
  • fileBuffer的内容将记录到控制台。
  • 此时,控制到达程序的末尾,因此它返回节点。这是第一个滴答声的结束。由于存在挂起的I / O,节点不会退出。
  • 节点进入"空闲"州。事件循环在无限循环中检查事件队列中的新项。许多蜱虫经过,直到......
  • 异步I / O操作最终完成,并将结果添加到事件队列中。下一个tick会将事件从队列中弹出,并调用最初传递给readFile的回调函数。
  • data的内容将记录到控制台,并且回调函数将返回。
  • 勾号已经结束,没有更多待处理的工作。节点退出。

答案 1 :(得分:1)

  1. Node是单线程的。阻塞调用正在执行时,没有任何反应。不会触发任何事件,也不会执行任何回调。这就是为什么在Node节点中始终强烈阻止阻塞调用的原因。 ReadFileSync应该用于命令行脚本,或者可能用于引导您的应用程序。
  2. 不太确定你究竟是在问什么。在列出的示例中,回调接收(非常常见)两个参数。一个是nullError实例,另一个是数据。此方法接收Buffer作为第二个参数。将缓冲区转换为字符串的快捷方式是data.toString(),它将字节列表转换为UTF-8编码字符串。
  3. 您会注意到几乎每个Node模块都使用此回调签名;一个可选的Error,然后是数据。

    从命令行运行时,您会注意到应用程序在最后一次IO操作完成时退出。 Node会跟踪自己。构建Web应用程序时,打开的HTTP(S)连接将使进程“忙碌”。