NPM酷库,每天两分钟,了解一个流行NPM库。
流
做下载等功能时候,我们经常会使用数据流模块(stream),因为,在大文件下载场景下,如果使用fs.readFile()
接口将文件全部读入内存然后再返回给客户端,很容易撑爆内存,比如一个文件200M,同时有100人在下载,那么服务就需要占用10G 内存。
而使用stream,我们不会将文件全部读入内存,而只是在内存中建立一个“水管”,所以内存中不会堆积过多数据:
ctx.body = fs.createReadStream('filename.ext');
上述代码中,我们使用fs.createReadStream()
方法创建了一个可读流,Koa会直接读取数据流,并返回给客户端。
双向流
如果一个流同时可读、可写,那么这就是一个双向流。“水管”不适合解释双向流,我们用“电话线”来解释,你说的话(写数据)对方能听见(读数据),同时,对方说话(写数据)你也能听见(读数据)。
妙用双向流在很多时候能解决很复杂的问题,比如,数据库导出场景。因为数据库里数据巨大,所以不能一下子读到Node.js内存中,我们可以创建一个只写流,从数据库逐条读出数据然后调用只写流,将数据写入磁盘,所有数据全部导出到磁盘后,再参照上文创建一个只读流,再将文件返回给客户端。但是这样存在问题的:
- 对磁盘大小有要求
- 在数据库导出到磁盘的过程中,客户端接受不到任何信息,很可能会造成浏览器超时访问
- 白白消耗系统性能,浪费磁盘IO
接下来我们就用双向流解决这个问题:
through
使用 through 可以快速创建一个双向流,相比自己调用stream模块创建双向流,through更方便,因为through已经封装了资源回收等机制。
const through = require('through');
// ...
const stream = through();
ctx.body = stream;
Order.find()
.cursor()
.eachAsync(async(order)=>{
stream.write(order.toJSON());
})
.then(()=>{
stream.end();
});
上述代码中,首先创建了一个双向流,返回给Koa,然后以Mongoose模型举例,查询数据库,并使用查询游标(cursor)逐条向流中写数据。在流的另一端,Koa就能逐条读出数据并返回给客户端。
参考资料
https://github.com/dominictar...
https://nodejs.org/api/stream...
欢迎关注公众号:梁兴臣
每天了解一个NPM库,一年后成为Node.js高手
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。