如何创建一个Node.js代理可读流来包装另一个';在创建代理流时,s不可用?
我可以发出一个简单的HTTP请求并返回一个流 但是,如果我必须发出一个HTTP请求,然后轮询以确定数据是否准备好,然后再发出另一个请求以获取数据,该怎么办 我想在一个返回流的方法中完成这一切,这样我就可以:如何创建一个Node.js代理可读流来包装另一个';在创建代理流时,s不可用?,node.js,stream,Node.js,Stream,我可以发出一个简单的HTTP请求并返回一个流 但是,如果我必须发出一个HTTP请求,然后轮询以确定数据是否准备好,然后再发出另一个请求以获取数据,该怎么办 我想在一个返回流的方法中完成这一切,这样我就可以: multiStepMethod(options).pipe(wherever); 而不是: multiStepMethod(options, (err, stream) => { stream.pipe(wherever); }) 我需要multiStepMethod返回一
multiStepMethod(options).pipe(wherever);
而不是:
multiStepMethod(options, (err, stream) => {
stream.pipe(wherever);
})
我需要multiStepMethod返回一个代理可读流,该流将等待某个事件,然后包装(现在可用)流并开始将其数据发送到管道中。#/usr/bin/env节点
#!/usr/bin/env node
'use strict';
const stream = require('stream');
// This is an example of a 'readable' stream that has to go through a multi-
// step process to finally get the actual readable stream. So we are
// asynchronously wrapping another readable stream.
// The key to simplicity here was to use a transform stream instead of a
// readable stream because it allows us to pipe the stream to ourselves.
class ReadableWrappingTransform extends stream.Transform {
constructor() {
super({
objectMode: true,
// Our _transform method doesn't really do anything and we don't want to
// hog up any more additional memory than necessary.
highWaterMark: 1
});
process.nextTick(() => {
if (new Date().getTime() % 5 === 1) {
// Here we simulate an error that happened somewhere in the multi-step
// process to get the final stream. So we just emit 'error' and we're
// done.
this.emit('error', new Error('Could not get the stream.'));
//Assuming based on the node docs that we should not emit
// 'close' or 'end' on error. If we do emit 'end', it will trigger the
// writable's 'finish' event, which is probably not desired. You either
// want an 'error' OR a 'finish'.
// NODE END EVENT DOCS
// The 'end' event is emitted when there is no more data to be consumed
// from the stream.
// Note: The 'end' event will not be emitted unless the data is
// completely consumed. This can be accomplished by switching the stream
// into flowing mode, or by calling stream.read() repeatedly until all
// data has been consumed.
// this.emit('end');
// NODE CLOSE EVENT DOCS
// The 'close' event is emitted when the stream and any of its
// underlying resources (a file descriptor, for example) have been
// closed. The event indicates that no more events will be emitted, and
// no further computation will occur.
// Not all Readable streams will emit the 'close' event.
// this.emit('close');
} else {
// We successfully got the stream we wanted after a long, hard, multi-
// step process, so first we need to copy all our listeners over to it
// -- NOT.
// ['close', 'data', 'end', 'error'].forEach((eventName) => {
// this.listeners(eventName).forEach((l) => {
// readable.on(eventName, l);
// });
// });
// Turns out that .pipe propagates ALL listeners EXCEPT the 'error'
// listener. What's up with that !?! If we copy any of the others we
// get double the events -- including double the data. So here we just
// copy over the 'error' listener to make sure we get 'error' events.
['error'].forEach((eventName) => {
this.listeners(eventName).forEach((l) => {
readable.on(eventName, l);
});
});
// Then just pipe the final readable to ourselves, and we are good.
readable
.pipe(this);
}
});
}
_transform(data, encoding, callback) {
// Nothing special to do here just pass along the data.
this.push(data);
callback();
}
}
// This is just a very unreliable test readable stream.
const readable = new stream.Readable({
objectMode: true,
read() {
for (let i = 0; i < 10; i++) {
if (new Date().getTime() % 13 === 1) {
this.__err = new Error('Sorry, error reading data.');
this.emit('error', this.__err);
return;
}
this.push({
Name: `Mikey ${i}`
});
}
this.push(null);
}
});
// Any old writable that we can pipe to.
const writable = new stream.Writable({
objectMode: true,
write(chunk, encoding, callback) {
console.log(chunk, encoding);
callback();
}
});
new ReadableWrappingTransform()
// if your stream emits close you get close.
.on('close', () => {
console.error('CLOSE');
})
// if you push null you get end from read.
.on('end', () => {
console.error('END');
})
// error needs to be both places !?! seriously node?
.on('error', (error) => {
console.error('ERROR', error);
})
// Finish does no good here. It's a writable event.
// .on('finish', () => {
// console.error('FINISH');
// })
.pipe(writable)
// Close and End do no good here, they are readable events.
// They are not propagated to the writable.
//
// // if your stream emits close you get close.
// .on('close', () => {
// console.error('CLOSE');
// })
// // if you push null you get end from read.
// .on('end', () => {
// console.error('END');
// })
// error needs to be both places !?! seriously node?
.on('error', (error) => {
console.error('ERROR', error);
})
// you should always get either finish or error or something was done
// incorrectly.
.on('finish', () => {
console.error('FINISH');
});
"严格使用",;
const stream=require('stream');
//这是一个“可读”流的示例,它必须通过多个-
//步骤处理,以最终获得实际的可读流。所以我们是
//异步包装另一个可读流。
//这里简单的关键是使用转换流而不是
//可读流,因为它允许我们通过管道将流传送给自己。
类ReadableWrappingTransform扩展了stream.Transform{
构造函数(){
超级({
objectMode:true,
//我们的_变换方法实际上没有做任何事情,我们也不想做
//占用不必要的额外内存。
高水位:1
});
process.nextTick(()=>{
如果(新日期().getTime()%5==1){
//在这里,我们模拟了多步骤过程中发生的错误
//进程以获取最终流。因此,我们只发出“error”,然后
//完成了。
this.emit('error',new error('无法获取流');
//假设基于我们不应该发出的节点文档
//出现错误时“关闭”或“结束”。如果我们发出“结束”,它将触发
//writable的“finish”事件,这可能是不需要的
//想要一个“错误”或“完成”。
//节点结束事件文档
//当没有更多数据要使用时,将发出“end”事件
//从小溪里。
//注意:“结束”事件将不会发出,除非数据
//完全消耗。这可以通过切换流来实现
//进入流动模式,或通过反复调用stream.read()直到所有
//数据已被消耗。
//这个.emit('end');
//节点关闭事件文档
//“close”事件在流及其任何
//底层资源(例如文件描述符)已被删除
//已关闭。该事件表示不再发出任何事件,并且
//不会进行进一步的计算。
//并非所有可读流都将发出“关闭”事件。
//这个.emit('close');
}否则{
//经过漫长、艰苦、多次的努力,我们成功地获得了我们想要的信息流-
//第一步,我们需要将所有侦听器复制到它
//”“没有。
//['close','data','end','error'].forEach((eventName)=>{
//this.listeners(eventName).forEach((l)=>{
//可读。on(事件名称,l);
// });
// });
//结果表明.pipe传播除“error”之外的所有侦听器
//听众,怎么回事!?!如果我们复制其他人的话
//获取双倍的事件,包括双倍的数据
//复制“错误”侦听器以确保获得“错误”事件。
['error'].forEach((eventName)=>{
this.listeners(eventName).forEach((l)=>{
可读。on(事件名称,l);
});
});
//然后就把最后的可读性给我们自己,我们就好了。
可读的
.管道(本);
}
});
}
_转换(数据、编码、回调){
//这里没有什么特别的事情,只是传递数据。
这个.推(数据);
回调();
}
}
//这只是一个非常不可靠的测试可读流。
const readable=新流。readable({
objectMode:true,
读(){
for(设i=0;i<10;i++){
如果(新日期().getTime()%13==1){
这是。uu err=新错误('对不起,读取数据时出错');
this.emit('error',this.\u err);
返回;
}
这个,推({
姓名:`Mikey${i}`
});
}
这个.push(null);
}
});
//任何我们可以通过管道传输的旧可写文件。
const writable=新流。可写({
objectMode:true,
写入(块、编码、回调){
log(块,编码);
回调();
}
});
新的ReadableWrappingTransform()
//如果你的溪流靠近,你就会靠近。
.on('关闭',()=>{
控制台错误(“关闭”);
})
//若你们按下null键,你们将从read中得到end。
.on('end',()=>{
console.error('END');
})
//错误必须是两个位置!?!认真点?
.on('错误',(错误)=>{
console.error('error',error);
})
//结束在这里没有好处。这是一个可写的事件。
//.on('finish',()=>{
//console.error('FINISH');
// })
.pipe(可写)
//“结束”和“结束”在这里没有任何用处,它们是可读的事件。
//它们不会传播到可写对象。
//
////如果您的流发出接近的信号,您就接近了。
//.on('关闭',()=>{
//控制台错误(“关闭”);
// })
////如果按null键,则从读取中得到结束。
//.on('end',()=>{
//console.error('END');
// })
//错误必须是两个位置!?!认真点?
.on('错误',(错误)=>{
console.error('error',error);
})
//你应该总是得到要么完成,要么出错,要么完成了某件事
//不对。
.on('finish',()=>{
console.error('FINISH');
});
#/usr/bin/env节点
"严格使用",;
const stream=require('stream');
//这是一个“可读”流的示例,它必须通过多个-
//步骤处理,以最终获得实际的可读流。所以我们是
//异步包装另一个可读流。
//这里简单的关键是使用转换流而不是
//可读流贝库