node.js:创建连接的可写和可读流对

时间:2018-09-22 09:06:00

标签: node.js stream

我正在尝试创建一个函数,该函数返回连接的可写和可读流对。例如:

const { writable, readable } = createStreamPair();

与PassThrough流不同,每个端点具有正确的接口(writable instanceof stream.Readable === falsereadable instanceof stream.Writable === false)。

用例:

createWriteStream(filePath) {

    const { writable, readable } = createStreamPair();
    writeFile(filePath, readable);
    return writable;
}

如何创建我的createStreamPair()函数?

编辑1

天真的方法显然行不通...

function createStreamPair() {

    var readable = new stream.Readable();
    var writable = new stream.Writable();
    readable.pipe(writable);
    return { writable, readable }
}

1 个答案:

答案 0 :(得分:1)

Node.js测试使用一个函数,该函数创建两个双工流,可以从另一个中读取对一个的写入,反之亦然:https://github.com/nodejs/node/blob/master/test/common/duplexpair.js

它不是Node.js标准库的一部分,但是您可以编写自己的代码。

我将在此处显示一个经过稍微修改的带注释的版本:

const Duplex = require('stream').Duplex;
const assert = require('assert');

// Define some unique property names.
// The actual value doesn't matter,
// so long as they're not used by Node.js for anything else.
const kCallback = Symbol('Callback');
const kOtherSide = Symbol('Other');

// Define a function `DuplexSocket` whose prototype inherits from `Duplex`
class DuplexSocket extends Duplex {
    constructor() {
        // Let Node.js initialize everything it needs to
        super();
        // Define two values we will be using
        // kCallback saves a temporary reference to a function while
        this[kCallback] = null;
        // kOtherSide will be the reference to the other side of the stream
        this[kOtherSide] = null;
    }

    _read() {
        // This is called when this side receives a push() call
        // If the other side set a callback for us to call,
        // then first clear that reference
        // (it might be immediately set to a new value again),
        // then call the function.
        const callback = this[kCallback];
        if (callback) {
            this[kCallback] = null;
            callback();
        }
    }

    _write(chunk, encoding, callback) {
        // This is called when someone writes to the stream
        // Ensure there's a reference to the other side before trying to call it
        assert.notStrictEqual(this[kOtherSide], null);
        // Ensure that the other-side callback is empty before setting it
        // If push immediately calls _read, this should never be a problem
        assert.strictEqual(this[kOtherSide][kCallback], null);
        // Let Node.js know when _read has been called
        this[kOtherSide][kCallback] = callback;
        // And finally, send the other side the data to be read
        this[kOtherSide].push(chunk);
    }

    _final(callback) {
        // Ask the other side to let us know it received our EOF request
        this[kOtherSide].on('end', callback);
        // And finally, pushing null signals the end of the stream
        this[kOtherSide].push(null);
    }
}

function makeDuplexPair() {
    // Create two pairs of 
    const clientSide = new DuplexSocket();
    const serverSide = new DuplexSocket();
    // Set the other-side reference
    clientSide[kOtherSide] = serverSide;
    serverSide[kOtherSide] = clientSide;
    // Both instances behave the same, so choice of name doesn't matter,
    // So long as they're distinguishable.
    return { clientSide, serverSide };
}

module.exports = makeDuplexPair;

这里是创建两个流的另一种方法,在这种情况下,一个是可读的,一个是可写的:

function makeAsymmetricalStreamPair() {
    var readableCallback;
    const readableSide = new ReadableStream;
    readableSide._read = function _read(){
        if(!readableCallback) return;
        var callback = readableCallback;
        readableCallback = null;
        callback();
    }
    const writableSide = new WritableStream;
    writableSide._write = function _write(chunk, enc, callback){
        if(readableCallback) throw new Error;
        if(typeof callback==='function') readableCallback = callback;
        readableSide.push(chunk);
    }
    writableSide._final = function _final(callback){
        readableSide.on('end', callback);
        readableSide.push(null);
    }
    return { readableSide, writableSide };
}