Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/440.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 实现缓冲转换流_Javascript_Node.js_Stream - Fatal编程技术网

Javascript 实现缓冲转换流

Javascript 实现缓冲转换流,javascript,node.js,stream,Javascript,Node.js,Stream,我正试图实现一个具有缓冲一定数量数据的流。当此流通过管道传输到另一个流时,或者如果某个流使用了可读的事件,则此流应该刷新其缓冲区,然后简单地成为pass-through。问题是,此流将通过管道传输到许多其他流,并且当每个目标流被连接时,即使缓冲区已经被刷新到另一个流,也必须刷新缓冲区 例如: BufferStream实现stream.Transform,并保留一个512KB的内环缓冲区 ReadableStreamA通过管道传输到BufferStream BufferStream写入其环形缓冲区

我正试图实现一个具有缓冲一定数量数据的流。当此流通过管道传输到另一个流时,或者如果某个流使用了
可读的
事件,则此流应该刷新其缓冲区,然后简单地成为pass-through。问题是,此流将通过管道传输到许多其他流,并且当每个目标流被连接时,即使缓冲区已经被刷新到另一个流,也必须刷新缓冲区

例如:

  • BufferStream
    实现
    stream.Transform
    ,并保留一个512KB的内环缓冲区
  • ReadableStreamA
    通过管道传输到
    BufferStream
  • BufferStream
    写入其环形缓冲区,从
    ReadableStreamA
    读取数据。(数据是否丢失无关紧要,因为缓冲区会覆盖旧数据。)
  • BufferStream
    通过管道传输到
    writeablestreamb
  • writeablestreamb
    接收整个512KB缓冲区,并在从
    ReadableStreamA
    通过
    BufferStream
    写入数据时继续获取数据
  • BufferStream
    通过管道传输到
    writeablestreamc
  • writeablestreamc
    也会接收整个512KB缓冲区,但该缓冲区现在与
    writeablestreamb
    接收的缓冲区不同,因为此后有更多数据写入了
    BufferStream
  • 这在streams API中是可能的吗?我能想到的唯一方法是使用一个方法创建一个对象,该方法为每个目的地旋转一个新的直通流,这意味着我不能简单地通过管道进出它


    值得一提的是,我使用了旧的“流动”API,只需监听
    数据
    事件上的新处理程序。在('data')上附加了一个新函数时,我会用一个环形缓冲区的副本直接调用它。

    以下是我对您的问题的看法

    基本思想是创建一个
    Transform
    流,这将允许我们在流的输出上发送数据之前执行自定义缓冲逻辑:

    var util = require('util')
    var stream = require('stream')
    
    var BufferStream = function (streamOptions) {
      stream.Transform.call(this, streamOptions)
      this.buffer = new Buffer('')
    }
    
    util.inherits(BufferStream, stream.Transform)
    
    BufferStream.prototype._transform = function (chunk, encoding, done) {
      // custom buffering logic
      // ie. add chunk to this.buffer, check buffer size, etc.
      this.buffer = new Buffer(chunk)
    
      this.push(chunk)
      done()
    }
    
    然后,我们需要重写
    .pipe()
    方法,以便在
    缓冲流
    通过管道传输到流中时收到通知,从而允许我们自动向其中写入数据:

    BufferStream.prototype.pipe = function (destination, options) {
      var res = BufferStream.super_.prototype.pipe.call(this, destination, options)
      res.write(this.buffer)
      return res
    }
    
    这样,当我们编写
    buffer.pipe(someStream)
    时,我们按照预期执行管道,并将内部缓冲区写入输出流。在那之后,
    Transform
    类处理所有事情,同时跟踪背压等等


    这是一本书。请注意,我没有费心编写正确的缓冲逻辑(即,我不关心内部缓冲区的大小),但这应该很容易解决。

    Paul的回答很好,但我认为它不符合确切的要求。听起来需要做的是,每次在此转换流上调用pipe(),它都需要首先刷新缓冲区,该缓冲区表示在创建转换流/(连接到源流)和连接到当前可写/目标流之间的所有数据累积

    类似这样的说法可能更正确:

      var BufferStream = function () {
            stream.Transform.apply(this, arguments);
            this.buffer = []; //I guess an array will do
        };
    
        util.inherits(BufferStream, stream.Transform);
    
        BufferStream.prototype._transform = function (chunk, encoding, done) {
    
            this.push(chunk ? String(chunk) : null);
            this.buffer.push(chunk ? String(chunk) : null);
    
            done()
        };
    
        BufferStream.prototype.pipe = function (destination, options) {
            var res = BufferStream.super_.prototype.pipe.apply(this, arguments);
            this.buffer.forEach(function (b) {
                res.write(String(b));
            });
            return res;
        };
    
    
        return new BufferStream();
    
    我想:

    BufferStream.super_.prototype.pipe.apply(this, arguments);
    
    相当于:

    stream.Transform.prototype.pipe.apply(this, arguments);
    

    您可能可以对此进行优化,并在调用管道/取消管道时使用一些标志。

    疑问:数据是否仅在512KB突发中移动,还是只有第一个是512KB?@user568109当某个对象开始从缓冲流接收数据时,它应该接收初始的512KB缓冲区(仅一次)然后,当数据通过缓冲流时,当数据变得可用时,将继续接收数据。只有第一个块是512KB(或者缓冲区的大小)。我认为这很接近,但不是100%正确。在第一次调用管道之前,转换实现需要将所有内容都放在缓冲区中,然后在调用管道后,切换到调用this.push。还有
    \u flush()
    方法呢当然,问题是它正在缓冲所有数据,并且从不停止缓冲,因此,如果不小心,这很容易导致内存“泄漏”。可能适合短期程序,但不适合服务器等。