在Node.js流中一直实现背压

时间:2017-01-14 09:29:48

标签: javascript node.js

我刚刚创建了一个简单的可读和可写流对,可以用pipe()连接。我感兴趣的是创建背压并控制Readable中读取的速率。但是我对如何实际实现它或者Node.js流是否可行感到困惑。 举个例子:

   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被调用'将被记录5次,早在Writable中的write方法看到数据之前很久。

我想要做的是只在Writable中的write方法触发其回调时才在Readable中调用read();当然read()方法必须首先触发一次,但随后会等待writeable准备就绪。

有没有办法控制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);

1 个答案:

答案 0 :(得分:2)

Node.js流非常强大,可以缓冲缓冲和数据流通过它们。

现在回答你的问题:

A)您会看到所有正在读取的数据,然后因为您的数据流非常小而触发了写入。如果使用Kilobytes数据进行测试,您将看到按顺序读取流和写入流。该序列取决于读取流的缓冲容量和写入流产生的背压。例如,TCP套接字读取流将比磁盘文件写入流快得多,从而产生背压。

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

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);
        }
    });
}

highWaterMark的较小值会很快产生背压,对某些用例(例如读取网络数据)可能会有不良影响。

C)您还可以控制读取流和写入流中的数据流。如果您的应用程序需要它,那么您可以控制可写流中的可读流。具体方法readable.pause()readable.read([size])readable.resume()readable.push(chunk[, encoding])readable.unpipe([destination])可让您控制缓冲和放大可读流中的数据流(甚至来自可写流)。实际上,您甚至可以使用方法readable.unshift(chunk)将数据从可写流推送回可读流。 有类似的方法可以控制可写流中的数据。

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

我强烈建议您阅读Node.js documentation on streams。它会为您提供大量信息(超过您在各种其他网站上可以找到的示例代码)。

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