[英]Is there any way to work with a Node stream as an iterable?
我正在編寫一個工具來處理傳遞給stdin
的一堆文本,每一行都是一個“條目”。 我想讓我的代碼更具功能性,所以我想將這組行視為“序列”或“可迭代”,並使用reduce
迭代它。
我目前正在使用Node模塊LineStream來處理stdin
作為一組行,但它通過為每一行調度data
事件來工作 - 這很好,它正在實現可讀流接口。
因此,每次data
事件觸發時,我都會通過將臨時值傳遞給我的函數來進行非常“手動”的縮減:
var windows = [];
linestream.on('data', function(line) {
return windows = rollup(windows, extractDate(line), argv.w);
});
linestream.on('end', function() {
return process.stdout.write(toCsv(windows));
});
process.stdin.resume();
但是做一些像以下事情更有用的功能:
linestream.lines.reduce(rollup, []);
function rollup(windows, line) {
// would return a new interim or final value
}
當然,我可以將所有行“收集”到一個常規數組然后減少它,但是我嘗試了它並且當我在一個大型數據集上運行我的工具時它使用了太多的內存 - 所以就像在流上迭代一樣真的是必要的。
我想我要問的是,是否可以編寫一個Node函數/模塊來執行此操作,或者是否已經存在。
謝謝!
我不相信有任何方法可以使它更具功能性,因為你正在處理異步性問題。
對於存在linestream.lines
,我認為需要做以下兩件事之一:
我想你可以這樣做(假設使用jquery或其他一些承諾api):
var op = (function(){
var windows = []
,done = $.deferred();
linestream.on('data', function(line) {
return windows = rollup(windows, extractDate(line), argv.w);
});
linestream.on('end', function() {
process.stdout.write(toCsv(windows));
return done.resolve(windows);
});
process.stdin.resume();
return done.promise();
})();
但實際上這只是隱藏的東西。
我不太明白rollup
應該做什么,但正如其他人所說的那樣,你不能擁有一個reduce函數,它希望一次擁有所有數據而不需要同時擁有所有數據和內存。
但是,您可以做的只是在數據事件回調中執行簡化邏輯。 如果它需要更多狀態,例如最后一個值或值的總數,則可以將該數據保留在回調周圍的閉包中。
例如,這是異步數字流的滾動平均值。
var total = 0;
var items = 0;
var average;
stream.on('data', function (line) {
var num = parseInt(line, 10);
total += line;
items++;
average = total / items;
});
stream.on('end', function () {
console.log("The average is %s", average);
});
在這個例子中,我從每行中獲取相關數據,並保留足夠的額外數據以始終了解我的上下文。 在這種情況下,我正在計算平均值,因此需要知道有多少項目。
你已經以功能的方式做到了這一點。 您正在偵聽事件,並在該事件觸發時運行函數,它不能比這更具功能性。
你是第二個例子,不改變功能,它仍然像第一個例子一樣有用。 然而,它改變的是運行該函數的源。 Reduce依賴於大量數據,同時存儲在內存中,正如您所說,這會導致非常大的內存占用。
如果我是你,我會繼續使用默認節點方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.