【发布时间】:2019-11-06 11:05:52
【问题描述】:
我为 nodejs 中内置的 readlines 模块构建了一个简单的异步实现,它只是基于事件的模块本身的一个包装器。代码如下;
const readline = require('readline');
module.exports = {
createInterface: args => {
let self = {
interface: readline.createInterface(args),
readLine: () => new Promise((succ, fail) => {
if (self.interface === null) {
succ(null);
} else {
self.interface.once('line', succ);
}
}),
hasLine: () => self.interface !== null
};
self.interface.on('close', () => {
self.interface = null;
});
return self;
}
}
理想情况下,我会在这样的代码中使用它;
const readline = require("./async-readline");
let filename = "bar.txt";
let linereader = readline.createInterface({
input: fs.createReadStream(filename)
});
let lines = 0;
while (linereader.hasLine()) {
let line = await linereader.readLine();
lines++;
console.log(lines);
}
console.log("Finished");
但是,我发现这个异步包装器出现了一些不稳定和意外的行为。一方面,它无法识别文件何时结束,并且在到达最后一行时简单地挂起,从不打印“Finished”。最重要的是,当输入文件很大时,比如几千行,它总是偏离几行,并且在停止之前没有成功读取完整文件。在一个超过 2000 行的文件中,它可能会减少多达 20-40 行。如果我向.on('close' 监听器中抛出一个打印语句,我看到它确实触发了;但是,程序仍然无法识别它不应再有要读取的行。
【问题讨论】:
-
看起来
line事件在极少数情况下会同步触发多次,因此下一个事件会在您的承诺解决和安装下一个once处理程序之前发生。 -
关于最后一行:在
close事件触发之前,您正在调用hasLine()和readLine(),而self.interface仍然不是null。它会等待下一个line事件,而这永远不会发生。 -
你应该看看异步迭代器和
for await … of。我想已经有一些可行的解决方案来解决如何将readline之类的事件发射器转换为这样的异步迭代器。 -
您有什么解决方案可以提出来吗?这似乎是
readlines模块或一般异步代码的根本缺陷。 -
不,根本缺陷是试图像你一样从事件中创建一个 Promise 接口。
readlines模块应该与回调样式一起使用,而您编写适配器的尝试还不够。
标签: node.js file asynchronous promise async-await