Node.js中的流十分强大,它对处理潜在的大文件提供了支持,也抽象了一些场景下的数据处理和传递。正因为它如此好用,所以在实战中我们常常基于它来编写一些工具 函数/库 ,但往往又由于自己对流的某些特性的疏忽,导致写出的 函数/库 在一些情况会达不到想要的效果,或者埋下一些隐藏的地雷。本文将会提供两个在编写基于流的工具时,私以为有些用的两个tips。
一,警惕EVENTEMITTER内存泄露
在一个可能被多次调用的函数中,如果需要给流添加事件监听器来执行某些操作。那么则需要警惕添加监听器而导致的内存泄露:
'use strict'; const fs = require('fs'); const co = require('co'); function getSomeDataFromStream (stream) { let data = stream.read(); if (data) return Promise.resolve(data); if (!stream.readable) return Promise.resolve(null); return new Promise((resolve, reject) => { stream.once('readable', () => resolve(stream.read())); stream.on('error', reject); stream.on('end', resolve); }) } let stream = fs.createReadStream('/Path/to/a/big/file'); co(function *() { let chunk; while ((chunk = yield getSomeDataFromStream(stream)) !== null) { console.log(chunk); } }).catch(console.error);
在上述代码中,getSomeDataFromStream函数会在通过监听error事件和end事件,来在流报错或没有数据时,完成这个Promise。然而在执行代码时,我们很快就会在控制台中看到报警信息:(node) warning: possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit.,因为我们在每次调用该函数时,都为传入的流添加了一个额外的error事件监听器和end事件监听器。为了避免这种潜在的内存泄露,我们要确保每次函数执行完毕后,清除所有此次调用添加的额外监听器,保持函数无污染:
function getSomeDataFromStream (stream) { let data = stream.read(); if (data) return Promise.resolve(data); if (!stream.readable) return Promise.resolve(null); return new Promise((resolve, reject) => { stream.once('readable', onData); stream.on('error', onError); stream.on('end', done); function onData () { done(); resolve(stream.read()); } function onError (err) { done(); reject(err); } function done () { stream.removeListener('readable', onData); stream.removeListener('error', onError); stream.removeListener('end', done); } }) }
二,保证工具函数的回调在处理完毕数据后才被调用
工具函数往往会对外提供一个回调函数参数,待处理完流中的所有数据后,带着指定值触发,通常的做法是将回调函数的调用挂在流的end事件中,但如果处理函数是耗时的异步操作,回调函数则可能在所有数据处理完毕前被调用:
'use strict'; const fs = require('fs'); let stream = fs.createReadStream('/Path/to/a/big/file'); function processSomeData (stream, callback) { stream.on('data', (data) => { // 对数据进行一些异步耗时操作 setTimeout(() => console.log(data), 2000); }); stream.on('end', () => { // ... callback() }) } processSomeData(stream, () => console.log('end'));
以上的代码callback回调可能会在数据并未被全部处理时就被调用,因为流的end事件的触发时机仅仅是在流中的数据被读完时。所以我们需要额外地对数据是否已处理完进行检查:
function processSomeData (stream, callback) { let count = 0; let finished = 0; let isEnd = false; stream.on('data', (data) => { count++; // 对数据进行一些异步耗时操作 setTimeout(() => { console.log(data); finished++; check(); }, 2000); }); stream.on('end', () => { isEnd = true; // ... check(); }) function check () { if (count === finished && isEnd) callback() } }
这样一来,回调便会在所有数据都处理完毕后触发了。
NODE.JS,流
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 罗大佑-无法盗版的青春套装版10CD【WAV】
- 张学友《意乱情迷》蜚声环球 2024 [WAV+CUE][1G]
- 柏菲《好歌30年特别版2CD》最好听的影视歌曲[低速原抓WAV+CUE][1G]
- 张学友《世纪10星·永恒篇》香港版[WAV+CUE][1G]
- 模拟之声慢刻CD《刘德海.琵琶独奏精逊【低速原抓WAV+CUE】
- Jamettone-18052023—improv(EDit)(2024)【FLAC】
- 【索尼精芽20首最棒的苏格兰歌曲集【FLAC】
- 池约翰C.J《少年白马醉春风2 动画原声带》[320K/MP3][26.67MB]
- 池约翰C.J《少年白马醉春风2 动画原声带》[FLAC/分轨][144.13MB]
- 陈致逸《幻想乐园 Fantasyland》[320K/MP3][120.54MB]
- 席卷全球最红舞曲《火辣辣DJ[英文版]》[DTS-WAV]
- 群星-席卷全球最红舞曲《火辣辣DJ中文版》【WAV】
- 模拟之声慢刻CD《声入人心[年度发烧人声严选]》[低速原抓WAV+CUE]
- 陈致逸《幻想乐园 Fantasyland》[FLAC/分轨][554.27MB]
- Rhymist / LusciousBB《年轮》[320K/MP3][76.52MB]