阅读线启动后定义事件处理程序

时间:2018-08-22 20:51:43

标签: node.js events fs

教科书中在NodeJS中逐行读取文件的方法似乎是调用readline.createInterface,然后再附加lineclose的事件处理程序。

似乎没有什么可以“启动”读者。它就可以了,并且似乎运行良好。如何知道何时开始阅读?如何保证那些尚不存在的事件将始终占用文件中的每一行?

我一直以为所有事件都发生得如此之快,以至于事件的附着速度要比从磁盘打开文件并开始读取文件的速度要快-但这并不能阻止。

例如,假设我在创建lineReader之后但在附加事件之前放置了一些占用大量CPU的代码。它似乎仍然有效,并且该事件仍在每一行触发。在开始阅读之前,它是如何“等”到繁重的工作完成的?如果我不附加line事件,那么无论如何它都会运行,并且close事件仍然会触发,所以这并不像它在等待line事件创建一样。

var lineReader = readline.createInterface({
    input: fs.createReadStream("input.txt")
});

// EVENTS HAVE NOT BEEN CREATED YET

lineReader.on("line", line => { console.log(line); });
lineReader.on("close", () => { console.log("DONE"); });

这不是lineReader特有的-似乎是常见的Node模式-这是最简单的定义和运行方式。

1 个答案:

答案 0 :(得分:1)

在内部,readline.createInterface()在创建流。默认情况下,流被暂停。他们以多种方式取消暂停,而与此相关的是添加了data事件侦听器之后。

然后在readline.createInterface()内添加一个data事件处理程序。这样一来,流就开始流动,它将开始发出data事件,readline代码将这些事件解析为行事件。

此外,因为node.js和流是事件驱动的,并且node.js以单线程方式运行Javascript,所以这意味着直到设置代码执行完毕才发生任何事件。在内部,node.js可能已经开始读取文件(内部使用异步I / O和线程),但是即使它在设置代码完成执行之前完成了对文件的第一次读取,它也会做的只是插入{{ 1}}事件在事件队列中。在您的设置代码完成执行并将控制权返回给node.js事件循环之前,node.js不会处理该data事件。

然后,将调用data事件回调,readline代码将解析来自第一个事件的数据,如果该第一个数据事件中有整行,则它将触发一个{{1} }事件。

  

似乎没有什么可以“启动”读者。

在readStream上(在readline代码内部)附加一个data事件处理程序是告诉流开始流动的原因。

  

它就去了,并且似乎运行良好。如何知道何时开始阅读?

与上述相同。

  

如何确保那些尚不存在的事件将始终拾取文件中的每一行?

readline代码在其line事件处理程序中从文件接收原始数据。然后,它将代码解析为几行,并为找到的每一行发出data事件。当文件读取越过行边界时,它必须缓冲部分行并等待行的其余部分出现在流中的下一个data事件中。

当行读取器代码看到流已完成读取并且没有更多字节时,它将发送最后一行(如果缓冲区中有一行),然后发出line事件以通知侦听器全部完成。

  

例如,假设我在创建lineReader之后但在附加事件之前放置了一些占用大量CPU的代码。它似乎仍然有效,并且该事件仍在每一行触发。它是如何“等”到繁重的工作完成之后才开始阅读的?

这是因为node.js是事件驱动的。流中的第一个data事件(在readline代码内部)是close函数的结果,它通过事件队列通知完成。在当前的Java语言片段完成并将控制权返回到事件循环之前,将不处理事件队列中的事件(届时它将为事件队列中等待的下一个事件提供服务)。因此,无论连接事件处理程序之前有多少占用CPU的代码,在完成所有操作之前,都不会告诉readline内部从文件读取的第一个数据。

这种单线程,事件驱动的特性可以确保在触发这些事件之前就可以安装事件侦听器,这样就无法错过它们。

  

如果我不附加line事件,那么无论如何它都会运行,并且close事件仍然会触发,因此就好像它在等待创建line事件一样。

正确。无论您是否有data事件监听器,readline代码都会在fs.readFile()调用内附加data事件处理程序。因此,无论您是否具有createInterface()事件处理程序,流都将开始流动,并且文件将被读取。


仅供参考,一种可以帮助您自己回答这些问题的方法是,只需查看一下node.js代码并查看其工作方式即可。那就是我在这里所做的。在a link to the createInterface() function处,您可以看到我在这里描述的内容。

然后,您会看到here in the stream doc,其中描述了流开始流动的三种方式,其中之一是附加了line事件侦听器。