Perkara yang perlu diberi perhatian semasa menulis alatan menggunakan strim dalam NODE.JS_node.js

WBOY
Lepaskan: 2016-05-16 15:12:48
asal
1005 orang telah melayarinya

Strim dalam Node.js sangat berkuasa Ia menyediakan sokongan untuk memproses fail yang berpotensi besar, dan juga pemprosesan dan penghantaran data abstrak dalam beberapa senario. Kerana ia sangat mudah untuk digunakan, dalam pertempuran sebenar kami sering menulis beberapa fungsi alat/perpustakaan berdasarkannya Namun, selalunya disebabkan oleh kecuaian kami terhadap ciri-ciri tertentu aliran, fungsi/pustaka yang kami tulis tidak akan memenuhi keperluan dalam beberapa kes. . kesan yang diingini, atau meletakkan beberapa lombong tersembunyi. Artikel ini akan memberikan dua petua yang saya fikir berguna semasa menulis alatan berasaskan aliran.

1. Berwaspada dengan kebocoran memori EVENTEMITTER

Dalam fungsi yang mungkin dipanggil beberapa kali, jika anda perlu menambah pendengar acara pada strim untuk melaksanakan operasi tertentu. Kemudian anda perlu berhati-hati dengan kebocoran memori yang disebabkan oleh penambahan pendengar:

'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);

Salin selepas log masuk

Dalam kod di atas, fungsi getSomeDataFromStream akan melengkapkan Promise apabila strim melaporkan ralat atau tiada data dengan mendengar peristiwa ralat dan acara tamat. Walau bagaimanapun, apabila melaksanakan kod, kami akan melihat mesej penggera dalam konsol: (nod) amaran: kemungkinan kebocoran memori EventEmitter dikesan 11 pendengar ralat ditambah Gunakan emitter.setMaxListeners() untuk meningkatkan had., kerana kami berada dalam setiap Setiap kali fungsi ini dipanggil, pendengar acara ralat tambahan dan pendengar acara tamat ditambahkan pada strim masuk. Untuk mengelakkan potensi kebocoran memori ini, kami perlu memastikan bahawa selepas setiap pelaksanaan fungsi, semua pendengar tambahan yang ditambahkan oleh panggilan ini dikosongkan untuk memastikan fungsi bebas pencemaran:

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);
  }
 })
}

Salin selepas log masuk

Kedua, pastikan panggilan balik fungsi alat dipanggil selepas memproses data

Fungsi alat selalunya menyediakan parameter fungsi panggil balik kepada dunia luar Selepas semua data dalam strim diproses, ia dicetuskan dengan nilai yang ditentukan Pendekatan biasa adalah untuk menggantung fungsi panggil balik dalam acara akhir strim , tetapi jika ia diproses Fungsi adalah operasi tak segerak yang memakan masa dan fungsi panggil balik boleh dipanggil sebelum semua data diproses:

'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'));

Salin selepas log masuk

Panggil balik kod di atas boleh dipanggil apabila semua data belum diproses, kerana peristiwa akhir strim hanya dicetuskan apabila data dalam strim dibaca. Jadi kita perlu menyemak tambahan sama ada data telah diproses:

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

Salin selepas log masuk

Dengan cara ini, panggilan balik akan dicetuskan selepas semua data diproses.

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan