举例讲解Node.js中的Writable对象
只要有玩过nodejs,那就一定接触过Writable。http模块的请求回调参数中的res参数就是一个Writable对象。我们经常会往上面write一堆东西,最后调用个end方法吧?这些都属于Writable的行为。
我们手动创建的Writable对象是交给用户使用的,那么write和end方法都是用户调用的。作为提供方,我们如何知道自己的Writable对象被用户执行了什么操作呢?就猜这个API吧,我首先会猜到某个事件。然而并不是!同Readable一样,它也得覆写某个方法来监听操作。下面是创建一个Writable让用户往里面写入内容,并监听用户到底写了什么的例子(基于babel-node):
importstreamfrom'stream'; varw=newstream.Writable; w._write=(buffer,enc,next)=>{ console.log(buffer+''); next();//触发「写入完成」 }; w.on('finish',()=>{ console.log('finish'); }); voidfunctioncallee(i){ if(i<10){ w.write(i+'','utf-8',()=>{ //写入完成 }); }else{ w.end(); } setTimeout(callee,10,i+1); }(0);
同Readable的_read一样,如果上面的_write没有被覆写将抛出异常:
Error:notimplemented atWritable._write(_stream_writable.js:430:6) atdoWrite(_stream_writable.js:301:12)
另外,write被设计为一个异步方法,它又第三个参数可以传入完成的回调。而所谓完成就是在实现函数_write中,next参数被调用。把write设计成异步是有原因的,如果它是同步执行,那么当我们需要在_write方法中处理一些异步事务时就可能产生顺序出错。比如一个磁盘文件的写操作就是一个异步的,如果我们写文件无视这个异步,那么假如上一个写操作被堵塞还没完成,当前的写操作可能会先执行。所以我们应该在_write中合理地调用next(必须调用,否则将陷入等待,无法继续写)。
最后,当数据写完成后会触发finish事件,这就意味着end方法被用户调用了。如果其间做的是写文件的操作,此时就应该关闭文件。