为什么我的.write方法中需要流API的回调?

问题描述

此问题与node.js流API的Writable.write方法中的回调有关。

我正在使用stream-adventure学习node.js流,它本质上是一种针对流的交互式教程。问题陈述之一是将process.stdin传递到调用console.log('writing' + chunk)自定义可写流。我的第一个解决方案是:

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

const writer = new Writable({
  write(chunk){
    console.log('writing: ' + chunk);
  }
})

process.stdin.pipe(writer);

输出(此行为是stream-adventure执行的测试的内部):

         Actual                                  Expected
   "writing: Screamer"                 ==    "writing: Screamer"
   ""                                  ==    ""
   ""                                  !=    "writing: Weeping Angel"
                                       !=    "writing: Sontaran"
                                       !=    "writing: Racnoss"
                                       !=    "writing: logopolitan"
                                       !=    "writing: Shansheeth"
                                       !=    "writing: Arcturan"
                                       !=    "writing: Cyberman"
                                       !=    "writing: Terileptil"
                                       !=    "writing: Ancient Lights"
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""
                                       !=    ""

我意识到使用流冒险会混淆该问题,因此请耐心等待。该流没有为下一次写入正确重置。在网上查看示例后,我使用以下方法解决了该问题:

const { stdin } = require('process');
const {Writable} = require('stream');

const writer = new Writable({
  write(chunk,encoding,next){
    console.log('writing: ' + chunk);
    next(); 
  }
})

process.stdin.pipe(writer);

这里唯一真正的区别是在写操作结束时执行回调。但是,我不知道为什么这样做。查看Writable类API,编码和回调都是可选的。大概是Readable.pipe方法将一些回调传递给,但这在文档中找不到。在第一种情况下,node.js到底在做什么,导致流停止,为什么在.write()中执行回调可以解决问题?

解决方法

内部_write()方法和公共write()方法之间的区别让我感到困惑。通常,write()方法不需要回调,而_write()确实需要回调。 _write()使用回调指示流已完成对当前块的处理。

Node API建议在创建可写流的新实例时,向对象提供_write()_writev()_final()方法。但是,当我实例化流时,我改为提供了write()方法。有趣的是,API文档将这种形式的流构造称为“简化”构造。

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

const myWritable = new Writable({
  write(chunk,encoding,callback) {
    // ...
  }
});

请注意,上面的列表现在不再列出,表示回调是可选的。我怀疑(但尚未确认)此语法会自动将_write()设置为与write()匹配。最终,这意味着我没有调用回调来表示块处理结束,因此可写流从未尝试处理下一个块。