用NODE.JS中的流寫工具是要注意的事項_node.js
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() } }
這樣一來,回呼便會在所有資料都處理完畢後觸發了。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

一開始的時候 JS 只在瀏覽器端運行,對於 Unicode 編碼的字串容易處理,但對於二進位和非 Unicode 編碼的字串處理困難。並且二進制是電腦最底層的資料格式,視訊/音訊/程式/網路包
