在readline启动后定义事件处理程序



在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模式——这只是最容易定义和运行的模式。

在内部,readline.createInterface()正在创建一个流。默认情况下,流会暂停。它们以多种方式解包,这里相关的是添加data事件侦听器。

并且,在readline.createInterface()内部,添加了一个data事件处理程序。这启动了流的流动,它将开始发出data事件,读取行代码将这些事件解析为行事件。

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

然后,将调用data事件回调,读线代码将解析第一个事件中的数据,如果第一个数据事件中有一整行,则它将触发line事件。

似乎没有任何东西可以"启动"读者。

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

它只是运行,而且似乎运行得很完美。它怎么知道什么时候开始阅读?

同上。

如何保证那些还不存在的事件总是会占用文件中的每一行?

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

当linereader代码看到流已经完成读取,并且没有更多的字节时,它会发送最后一行(如果缓冲区中有一行),然后发出close事件,告诉侦听器已经完成。

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

这是因为node.js是事件驱动的。流中的第一个data事件(读线代码内部)是fs.readFile()函数的结果,它通过事件队列通知完成。事件队列中的事件将不会被处理,直到当前Javascript完成并将控制权返回到事件循环(此时它将为事件队列中等待的下一个事件提供服务)。因此,无论在附加事件处理程序之前有多少消耗CPU的代码,在所有这些都完成之前,readline的内部都不会被告知从文件中读取的第一个数据。

正是这种单线程、事件驱动的特性确保了在触发这些事件之前安装事件侦听器,这样就不会错过它们。

如果我不附加行事件,那么它无论如何都会运行,关闭事件仍然会触发,所以它不像是在等待创建行事件。

正确。readline代码将data事件处理程序附加到createInterface()调用中,无论是否有line事件侦听器。因此,无论是否有line事件处理程序,流都将开始流动,文件都将被读取。


仅供参考,您可以帮助自己回答这些问题的一种方法是查看node.js代码,看看它是如何工作的。这就是我在这里所做的。这里有一个指向createInterface()函数的链接,您可以在这里看到我在这里描述的内容。

您可以在流文档中看到,其中描述了流开始流动的三种方式,其中之一是附加data事件侦听器。

最新更新