摘要:中的流十分強大,它對處理潛在的大文件提供了支持,也抽象了一些場景下的數據處理和傳遞。本文將會提供兩個在編寫基于流的工具時,私以為有些用的兩個。
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() } }
這樣一來,回調便會在所有數據都處理完畢后觸發了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78777.html
摘要:方法也可以接收一個參數表示數據請求著請求的數據大小,但是可讀流可以根據需要忽略這個參數。讀取數據大部分情況下我們只要簡單的使用方法將可讀流的數據重定向到另外形式的流,但是在某些情況下也許直接從可讀流中讀取數據更有用。 介紹本文介紹了使用 node.js streams 開發程序的基本方法。 We should have some ways of connecting programs ...
摘要:第四章引入流一什么是流流是的新成員,它允許你以聲明性方式處理數據集合通過查詢語句來表達,而不是臨時編寫一個實現。 第四章 引入流 一、什么是流 流是Java API的新成員,它允許你以聲明性方式處理數據集合(通過查詢語句來表達,而不是臨時編寫一個實現)。就現在來說,你可以把它們看成遍歷數據集的高級迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼。 下面兩段代碼都是用來返回低...
摘要:正在暑假中的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。原理微信熱更新方案漲知識了,熱更新是以后的標配。 正在暑假中的《課多周刊》(第1期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的動力。 遠上寒山石徑...
摘要:正在暑假中的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。原理微信熱更新方案漲知識了,熱更新是以后的標配。 正在暑假中的《課多周刊》(第1期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的動力。 遠上寒山石徑...
摘要:我們創建一個可讀流,并嘗試使用和來進行轉換,將最后得到的內容交給。它重新使用可讀流中的文件名,然后在必要時創建文件夾使用。使用常規可讀流時,你可以監聽事件來檢測數據碎片的到來不同的是,使用會將轉換成的文件對象重新寫入到流中。 本文翻譯自Getting gulpy -- Advanced tips for using gulp.js 感受過gulp.js帶來的興奮過后,你需要的不僅僅是...
閱讀 955·2019-08-30 14:24
閱讀 987·2019-08-30 14:13
閱讀 1799·2019-08-29 17:21
閱讀 2661·2019-08-29 13:44
閱讀 1654·2019-08-29 11:04
閱讀 438·2019-08-26 10:44
閱讀 2564·2019-08-23 14:04
閱讀 908·2019-08-23 12:08