我试图找到在Node.js中过早终止一系列管道流(管道)的正确方法:有时我想在流完成之前优雅地中止流。具体来说,我处理的主要是objectMode: true
和非本地并行流,但这并不重要。
问题是当我unpipe
管道时,数据保留在每个流的缓冲区中并且drain
被编辑。对于大多数中间流(例如Readable
/ Transform
),此可能没问题,但最后Writable
仍然会耗尽其写入目标(例如文件)或数据库或套接字或w / e)。如果缓冲区包含数百或数千个块需要花费大量时间来消耗,则这可能是有问题的。我想让它立即停止,即不要流失;为什么浪费周期和记忆数据并不重要?
根据我走的路线,我会收到一个"写完后#34;当流无法找到现有管道时出现错误或异常。
正确的方式以a.pipe(b).pipe(c).pipe(z)
的形式优雅地删除流的管道是什么?
我提出的解决方案是三步:
unpipe
管道中的每个流的顺序相反Writable
end
每个实现Writable
一些说明整个过程的伪代码:
var pipeline = [ // define the pipeline
readStream,
transformStream0,
transformStream1,
writeStream
];
// build and start the pipeline
var tmpBuildStream;
pipeline.forEach(function(stream) {
if ( !tmpBuildStream ) {
tmpBuildStream = stream;
continue;
}
tmpBuildStream = lastStream.pipe(stream);
});
// sleep, timeout, event, etc...
// tear down the pipeline
var tmpTearStream;
pipeline.slice(0).reverse().forEach(function(stream) {
if ( !tmpTearStream ) {
tmpTearStream = stream;
continue;
}
tmpTearStream = stream.unpipe(tmpTearStream);
});
// empty and end the pipeline
pipeline.forEach(function(stream) {
if ( typeof stream._writableState === 'object' ) { // empty
stream._writableState.length -= stream._writableState.buffer.length;
stream._writableState.buffer = [];
}
if ( typeof stream.end === 'function' ) { // kill
stream.end();
}
});
我真的很担心stream._writableState
的使用并修改内部buffer
和length
属性(_
表示私有财产)。这似乎是一个黑客。另请注意,由于我正在管道,pause
和resume
这样的问题我们无从谈起(基于我从IRC收到的建议)。
我还整理了一个可以从github获取的可运行版本(非常草率):https://github.com/zamnuts/multipipe-proto(git clone,npm install,view readme,npm start)
答案 0 :(得分:1)
在这个特殊情况下,我认为我们应该摆脱你有4个不完全定制的流的结构。将它们连接在一起将产生链依赖性,如果我们没有实现自己的机制,将难以控制。
我想在这里关注你的目标:
INPUT >----[read] → [transform0] → [transform1] → [write]-----> OUTPUT
| | | |
KILL_ALL------o----------o--------------o------------o--------[nothing to drain]
我相信上述结构可以通过组合自定义来实现:
duplex stream
- 使用
_write(chunk, encoding, cb)
和_read(bytes)
transform stream
- 用于自己的_transform(chunk, encoding, cb)
实施。
由于您使用的是
writable-stream-parallel
软件包,因此您可能还需要查看他们的库,因为duplex
实现可以在此处找到:https://github.com/Clever/writable-stream-parallel/blob/master/lib/duplex.js。 他们的transform stream
实施就在这里:https://github.com/Clever/writable-stream-parallel/blob/master/lib/transform.js。他们在这里处理highWaterMark。
可能的解决方案
他们的写入流:https://github.com/Clever/writable-stream-parallel/blob/master/lib/writable.js#L189有一个有趣的函数writeOrBuffer
,我想你可以稍微调整它来中断从缓冲区写入数据。
注意:这些3 flags正在控制缓冲区清除:
( !finished && !state.bufferProcessing && state.buffer.length )
<强>参考文献:强>