关于Node.js里面的Transform Stream类型

通常,Nodejs的Stream处理是异步的,这意味着,

(1)你不能连续写2条语句:buf = input,read(); output.write(buf)。

    为什么?前一句read是异步的,意味着语句执行完之后,实际上根本可能还没IO ready,没有获取到数据呢!——当然,异步IO是基于callback的,或者promise的。我这里是为了叙述的方便。

(2)所以,对异步IO,基于callback的写法应该是:

  input.read( (buf)=> { output.write(buf, ()=>{console.log("1 buf copy done!")}), })

或者Promise化的语法:

input.read().then( (buf)=> output.write(buf); )

Promise看起来像是个语法糖,但它与callback有本质的不同:callback的回调过程仍然是同步的,这意味着在深度嵌套callback的过程中,栈有可能溢出。

而对Promise而言,Promise的then仅仅代表向JS语言的执行环境状态机注册一个state change的callback。一个Promise可以串起多个then,但这些then每个都是单独从核心event loop直接dispatch的,因此不存在栈溢出的问题。

进一步的语法糖就是把Promise转换为ES7 async/await的写法。实际上是把Promise转换为了Future对象,当需要从Future对象实际get原始类型数据的时候,就会陷入IO-blocking wait状态了。不过这个IO-blocking wait的内部执行又是一个coroutine的context switch而已。实际上JS主线程并没有阻塞!

(3)但是注意一个问题:(2)的写法只能处理一次buf copy。假如我想连续发起多个buf copy呢?不行,做不到。

而且,对于Node.js的IO模型来说,IO buf的读写操作有可能不能一次性完成,可能拆分成多次完成,也有可能把连续多个小的读写操作合并到一个batch里面执行。

(4)这就意味着:异步IO模型无法完成下面的事情:

IO clone:即将一个input里的数据流同时送到两个output。(Node.js内置的input.pipe(output)只能处理1对1的情况)

(5)假如我想在input pipe到output的过程中,对数据流进行修改怎么办?Node.js提供了一种特殊的Filter Stream,即Transform Stream。

见名以知义,这种Transform必须是流式处理的。假如数据流的底层是固定的blocks,那还好办,但假如是一个很长的JSON字符串,而我们需要即时地修改JSON字符串中的某些value时,麻烦就来了:

    需要实现一个CFG parser!普通的FSM可能都不行。而且这个CFG parser必须是流式的处理风格,意味着它需要逐个char逐个char的feed in。而不是一次性传给它整个完整的Buffer。

    当然,对简单的处理来说,Transform可以一直在input read in的过程中,将数据缓存到一个大的Buffer对象,然后等待input read的finish事件,此时就可以把整个Buffer对象作为一个完整的JSON字符串来parse->modify->re-serialize的处理了。只不过有个疑问:在这个过程中,input本来期望是与output pipe的,结果实际却是input的read请求被满足了,output的write需要却一直被忽略,这有没有可能造成在output流上触发一个write timeout异常呢???


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值