用NODE.JS中的流編寫工具是要注意的事項,node.js編寫

來源:互聯網
上載者:User

用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() }}

這樣一來,回調便會在所有資料都處理完畢後觸發了。

您可能感興趣的文章:
  • 為什麼Node.js會這麼火呢?Node.js流行的原因
  • Node.js中的緩衝與流模組詳細介紹
  • 最流行的Node.js精簡型和全棧型開發架構介紹
  • Node.js中的流(Stream)介紹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.