Javascript 在Node.js流中一路实现背压

Javascript 在Node.js流中一路实现背压,javascript,node.js,Javascript,Node.js,我刚刚创建了一个简单的可读写流对,它可以与pipe()连接。我感兴趣的是创建背压和控制可读介质中读取发生的速率。然而,对于如何实际实现这一点,或者是否可以使用Node.js streams实现这一点,我有点困惑。 例如: const {Writable, Readable} = require('stream'); function getWritable() { return new Writable({ write: function

我刚刚创建了一个简单的可读写流对,它可以与pipe()连接。我感兴趣的是创建背压和控制可读介质中读取发生的速率。然而,对于如何实际实现这一点,或者是否可以使用Node.js streams实现这一点,我有点困惑。 例如:

   const {Writable, Readable} = require('stream');

    function getWritable() {
        return new Writable({
            write: function (chunk, encoding, cb) {
                console.log(' => chunk => ', String(chunk));
                setTimeout(cb, 1500);
            }
        });
    }


    function getReadable(data) {
        return new Readable({
            encoding: 'utf8',
            objectMode: false,
            read: function (n) {
                // n =>  Number(16384)
                console.log('read is called');
                const d = data.shift();
                this.push(d ? String(d) : null);
            }
        });
    }


    const readableStrm = getReadable([1, 2, 3, 4, 5]);

    const piped = readableStrm.pipe(getWritable());

    piped.on('finish', function () {
        console.log('finish');
    });
如果运行上述代码,我们将看到“read is called”将被记录5次,远远早于writeable中的write方法看到数据

我想做的是,当writeable中的write方法触发回调时,只调用Readable中的
read()
;当然,read()方法必须首先触发一次,但随后将等待可写文件准备就绪

有没有一种方法可以控制
read()

最后,我真的不明白
read()
方法的目的是什么

举个简单的例子,无论我从read()返回什么,我都无法让它停止读取。read方法的意义是什么,为什么我们必须实现它

const Readable = require('stream').Readable;

const r = new Readable({
    objectMode: true,
    read: function (n) {
        console.log('is read');
        return false/null/true;  // nothing I return here makes a difference
    }
});


r.on('data', function (d) {
    console.log(d);
});


setInterval(function(){
    r.push('valid');
},1000);

js流非常强大,在缓冲中提供了大量关于缓冲的控制以及通过它们的数据流

现在回答您的问题:

A)由于数据流非常小,您会看到所有数据都先被读取,然后被触发写入。如果您使用千字节的数据进行测试,您将看到读流和写流按顺序触发。顺序取决于读流的缓冲容量和写流产生的背压。例如,TCP套接字读取流将比磁盘文件写入流快得多,从而产生反压力

B)读写流的一个强大构造函数选项是
highWaterMark
。您可以在的缓冲部分了解更多信息
highWaterMark
专门定义可读/写流的缓冲容量。默认值为16kb。在上面的示例中,您可以使用highWaterMark将可读流设置为2个字节,如下所示,您将看到不同之处(在实际情况中不需要,但可以用于学习)

函数getReadable(数据){ 设i=0; 返回新流。可读({ Highwaterark:2,//编号(16384) log('称为read'); 常数d=数据[i++]; this.push(d?字符串(d):null); } }); }
highWaterMark
的值越小,将很快产生反压力,并且可能对某些用例(如读取网络数据)有害

C)您还可以控制读流和写流中的数据流。如果应用程序需要它,那么可以从可写流控制可读流。特定的方法、和允许您控制可读流(甚至是可写流)中的数据缓冲和流。事实上,您甚至可以使用方法将数据从可写流推回可读流。控制可写流中的数据也有类似的方法

D)读取和写入方法是流实现的一部分。这些方法用于将流数据发送到底层资源,不应直接从应用程序数据调用。基本上,它定义了流的设置。(不确定我是否能解释清楚)

我强烈建议您阅读Node.js。它会给你很多信息(比你在其他网站上找到的示例代码要多)


我希望以上信息对您有所帮助。

谢谢您的回答,我投了更高的票,因为它提供了信息,但很遗憾,我没有向我证明您所说的是真的。我正在寻找一些代码来演示read()方法的实际作用,以及read()中的返回值如何发挥作用。此外,我正在寻找一个合适的read()实现,它可以异步地获取数据。我担心的是,由于您正在使用这个函数,读取流的所有数据都将被缓冲到内存中。在read()中推送(X)…但是X从何而来?:)read的返回值似乎无关紧要,您可以异步调用this.push;然而,我认为如果API采用回调而不是期望用户调用this.push,那么就会更清晰。
function getReadable(data) {
    let i = 0;
    return new stream.Readable({
        highWaterWark: 2,  // <--- highWaterMark set to 2 byte. Preferably set it to 10 and increase the length of your input array.
        encoding: 'utf8',
        objectMode: false,
        read: function (n) {
            // n =>  Number(16384)
            console.log('read is called');
            const d = data[i++];
            this.push(d ? String(d) : null);
        }
    });
}