承诺链对于不覆盖节点中的流(请参阅Bergi的评论)非常有用。但这里有一个例子,在非同步微妙的情况下产生的写流错误命令写道:具有细微异步排序的承诺链
var fs = require('fs');
function WTest() {
this.writeStream = fs.createWriteStream('junkTest.txt');
this.readyToWrite = Promise.resolve(true);
};
WTest.prototype.writeNext = function writeNext(text, callNum) {
this.readyToWrite = this.readyToWrite
.then(status => writeToStream(text, this.writeStream, status, callNum));
}
var wTest = new WTest();
for (var i = 0; i < 10; i++) wTest.writeNext(
`${i}, some line of text that might be xxxxxxxxxxxxxxxxxxxxxxxx long \n`, i);
function writeToStream(text, writableStream, readyToWrite, callNum) {
return new Promise((resolve) => {
if (readyToWrite) resolve(writableStream.write(text));
else writableStream.once('drain',() => resolve(writableStream.write(text)));
});
}
如果你运行它是在节点7.8,它的工作原理。但在复杂的异步情况下,它会失败,例如一行是乱序写入的。上述代码有什么异步危险?你可以在失败的地方创建一个异步的例子吗?
我的故障实例包括多个异步文件读取,其中上述代码服务于记录器功能。我已经验证了writeNext调用在调用writeNext函数后立即将它们写入控制台以达到预期的顺序。正如在评论中提到的,我写了两个(都直接写入同一个文件),在promise写入(=)后立即直接写入“ - ”。输出文件中的行序列是1,1 =,2,3,4,5,6,7,8,2 =,7 =,3 =,4 =,5 = 6 =,9-,9 =,10-,10 =
Bergi的大图智慧:“防止重写的唯一方法是停止生成新块。所以以上只是技术上的兴趣。创建承诺链会恶化缓冲的内存成本。
“* A诺言链中节点不能过度写流*有用” - 不。你应该忽略'write'的返回值并继续写。当然,它会填充流的缓冲区,直到程序内存不足,但这仍然比缓冲承诺队列中的数据更有效。 – Bergi
我看到的唯一问题是,您可能会错过'drain'事件,因为您只有在有另一个块写入时才开始收听,而不是在您收到“false”后立即收听,但这会导致永远悬挂的流,而不会导致无序写入的行。请将您的实际代码发布为“*异常复杂情况*”,因为这可能是您以意外顺序调用writeNext的地方。 – Bergi
@Bergi我相信我不是以意想不到的顺序编写的,因为如果我用process.stdout.write存储调用writeNext的输出,则会按正确的顺序生成输出。 – Govdata1