Nodeを使うjsの中のストリーム書き込みツールの時の2点の小さいtips
3652 ワード
Node.js
のストリームは非常に強力で、潜在的な大きなファイルの処理をサポートし、いくつかのシーンでのデータの処理と伝達を抽象化しています.このように使いやすいからこそ、実戦ではツール関数/ライブラリを書くことが多いが、自分の対流のいくつかの特性の不注意によって、書かれた関数/ライブラリが所望の効果に達しない場合や、隠れた地雷を埋める場合がある.本稿では,ストリームベースのツールを記述する際に,いくつかの役に立つと思う2つのtipsを提供する.一、EventEmitterメモリの漏洩を警戒する
複数回呼び出される可能性のある関数では、ストリームにイベントリスナーを追加していくつかの操作を実行する必要がある場合.では、Listenerの追加によるメモリの漏洩に注意する必要があります.
'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
イベントリスナーが追加されるため、コンソールにアラーム情報が表示されます.このような潜在的なメモリ漏洩を回避するために、関数の実行が完了するたびに、今回の呼び出しで追加された追加のリスナーをすべて消去し、関数を汚染しないようにします.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'));
以上のコード
end
コールバックは、ストリームのcallback
イベントのトリガタイミングがストリーム中のデータが読み終わったときだけであるため、データがすべて処理されていないときに呼び出される可能性がある.データが処理されたかどうかをさらに確認する必要があります.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()
}
}
これにより、コールバックはすべてのデータが処理された後にトリガーされます.