承諾鏈對於不覆蓋節點中的流(請參閱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