用NODE.JS中的流編寫工具是要注意的事項(xiàng)
Node.js中的流十分強(qiáng)大,它對(duì)處理潛在的大文件提供了支持,也抽象了一些場(chǎng)景下的數(shù)據(jù)處理和傳遞。正因?yàn)樗绱撕糜?,所以在?shí)戰(zhàn)中我們常?;谒鼇砭帉懸恍┕ぞ?函數(shù)/庫 ,但往往又由于自己對(duì)流的某些特性的疏忽,導(dǎo)致寫出的 函數(shù)/庫 在一些情況會(huì)達(dá)不到想要的效果,或者埋下一些隱藏的地雷。本文將會(huì)提供兩個(gè)在編寫基于流的工具時(shí),私以為有些用的兩個(gè)tips。
一,警惕EVENTEMITTER內(nèi)存泄露
在一個(gè)可能被多次調(diào)用的函數(shù)中,如果需要給流添加事件監(jiān)聽器來執(zhí)行某些操作。那么則需要警惕添加監(jiān)聽器而導(dǎo)致的內(nèi)存泄露:
'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函數(shù)會(huì)在通過監(jiān)聽error事件和end事件,來在流報(bào)錯(cuò)或沒有數(shù)據(jù)時(shí),完成這個(gè)Promise。然而在執(zhí)行代碼時(shí),我們很快就會(huì)在控制臺(tái)中看到報(bào)警信息:(node) warning: possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit.,因?yàn)槲覀冊(cè)诿看握{(diào)用該函數(shù)時(shí),都為傳入的流添加了一個(gè)額外的error事件監(jiān)聽器和end事件監(jiān)聽器。為了避免這種潛在的內(nèi)存泄露,我們要確保每次函數(shù)執(zhí)行完畢后,清除所有此次調(diào)用添加的額外監(jiān)聽器,保持函數(shù)無污染:
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);
}
})
}
二,保證工具函數(shù)的回調(diào)在處理完畢數(shù)據(jù)后才被調(diào)用
工具函數(shù)往往會(huì)對(duì)外提供一個(gè)回調(diào)函數(shù)參數(shù),待處理完流中的所有數(shù)據(jù)后,帶著指定值觸發(fā),通常的做法是將回調(diào)函數(shù)的調(diào)用掛在流的end事件中,但如果處理函數(shù)是耗時(shí)的異步操作,回調(diào)函數(shù)則可能在所有數(shù)據(jù)處理完畢前被調(diào)用:
'use strict';
const fs = require('fs');
let stream = fs.createReadStream('/Path/to/a/big/file');
function processSomeData (stream, callback) {
stream.on('data', (data) => {
// 對(duì)數(shù)據(jù)進(jìn)行一些異步耗時(shí)操作
setTimeout(() => console.log(data), 2000);
});
stream.on('end', () => {
// ...
callback()
})
}
processSomeData(stream, () => console.log('end'));
以上的代碼callback回調(diào)可能會(huì)在數(shù)據(jù)并未被全部處理時(shí)就被調(diào)用,因?yàn)榱鞯膃nd事件的觸發(fā)時(shí)機(jī)僅僅是在流中的數(shù)據(jù)被讀完時(shí)。所以我們需要額外地對(duì)數(shù)據(jù)是否已處理完進(jìn)行檢查:
function processSomeData (stream, callback) {
let count = 0;
let finished = 0;
let isEnd = false;
stream.on('data', (data) => {
count++;
// 對(duì)數(shù)據(jù)進(jìn)行一些異步耗時(shí)操作
setTimeout(() => {
console.log(data);
finished++;
check();
}, 2000);
});
stream.on('end', () => {
isEnd = true;
// ...
check();
})
function check () {
if (count === finished && isEnd) callback()
}
}
這樣一來,回調(diào)便會(huì)在所有數(shù)據(jù)都處理完畢后觸發(fā)了。
相關(guān)文章
NodeJS通過魔術(shù)封包喚醒局域網(wǎng)計(jì)算機(jī)實(shí)例
這篇文章主要為大家介紹了NodeJS通過魔術(shù)封包喚醒局域網(wǎng)計(jì)算機(jī)代碼實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Node.js?中的服務(wù)器相關(guān)概念(常見的服務(wù)器任務(wù))
Node.js?中,服務(wù)器的創(chuàng)建與管理是非常重要的內(nèi)容,Node.js?的非阻塞?I/O?特性使得它特別適合處理高并發(fā)的請(qǐng)求,本文將介紹一些與?Node.js?服務(wù)器相關(guān)的基本概念,包括?HTTP?服務(wù)器、請(qǐng)求和響應(yīng)、路由、以及如何處理常見的服務(wù)器任務(wù),感興趣的朋友一起看看吧2025-04-04
Node.js前后端交互實(shí)現(xiàn)用戶登陸的實(shí)踐
本文主要介紹了Node.js前后端交互實(shí)現(xiàn)用戶登陸的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
詳解electron如何攔截網(wǎng)絡(luò)請(qǐng)求并處理響應(yīng)
這篇文章主要為大家詳細(xì)介紹了electron如何攔截網(wǎng)絡(luò)請(qǐng)求并處理響應(yīng),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
詳解node Async/Await 更好的異步編程解決方案
這篇文章主要介紹了詳解Async/Await 更好的異步編程解決方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05
如何從頭實(shí)現(xiàn)一個(gè)node.js的koa框架
這篇文章主要介紹了如何從頭實(shí)現(xiàn)一個(gè)node.js的koa框架,koa.js是最流行的node.js后端框架之一,有很多網(wǎng)站都使用koa進(jìn)行開發(fā),同時(shí)社區(qū)也涌現(xiàn)出了一大批基于koa封裝的企業(yè)級(jí)框架。,需要的朋友可以參考下2019-06-06
使用Node.js find-up在父目錄中高效尋找文件與目錄
find-up 是一個(gè)小巧但功能強(qiáng)大的 Node.js 包,它能幫助我們實(shí)現(xiàn)這一需求,本文將深入探究如何使用 find-up 進(jìn)行有效搜索,并結(jié)合豐富的代碼演示幫助大家快速掌握其用法,需要的朋友可以參考下2024-05-05
Node.js中的Buffer對(duì)象及創(chuàng)建方式
node.js提供了一個(gè)Buffer對(duì)象來提供對(duì)二進(jìn)制數(shù)據(jù)的操作,Buffer?類的實(shí)例類似于整數(shù)數(shù)組,但?Buffer?的大小是固定的、且在?V8?堆外分配物理內(nèi)存。本文給大家介紹Node.js中的Buffer對(duì)象及創(chuàng)建方式,感興趣的朋友一起看看吧2022-01-01
node.js(expree.js?)模擬手機(jī)驗(yàn)證碼登錄功能
這篇文章主要介紹了node.js(expree.js?)模擬手機(jī)驗(yàn)證碼功能及登錄功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01

