Node.js의 스트림은 매우 강력하며 일부 시나리오에서는 잠재적으로 큰 파일 처리와 추상 데이터 처리 및 전달을 지원합니다. 사용하기가 너무 쉽기 때문에 실제 전투에서는 이를 기반으로 일부 도구 기능/라이브러리를 작성하는 경우가 많습니다. 그러나 스트림의 특정 특성을 무시한 경우 작성된 기능/라이브러리가 어떤 경우에는 요구 사항을 충족하지 못할 수도 있습니다. . 원하는 효과를 얻거나 숨겨진 광산을 설치하세요. 이 기사에서는 스트림 기반 도구를 작성할 때 유용하다고 생각되는 두 가지 팁을 제공합니다.
1. 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 함수는 스트림이 오류를 보고하거나 데이터가 없을 때 오류 이벤트 및 종료 이벤트를 수신하여 Promise를 완료합니다. 그러나 코드를 실행하면 곧 콘솔에 다음과 같은 경보 메시지가 표시됩니다. (노드) 경고: 가능한 EventEmitter 메모리 누수가 감지되었습니다. 11개의 오류 리스너가 추가되었습니다. 제한을 늘리려면 Emitter.setMaxListeners()를 사용하세요. 이 함수가 호출될 때마다 추가 오류 이벤트 리스너와 종료 이벤트 리스너가 수신 스트림에 추가됩니다. 이러한 잠재적인 메모리 누수를 방지하려면 각 함수 실행 후 이 호출로 추가된 모든 추가 리스너가 지워져 함수가 오염되지 않도록 해야 합니다.
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); } }) }
둘째, 데이터 처리 후 도구 함수의 콜백이 호출되는지 확인하세요
도구 함수는 종종 외부 세계에 콜백 함수 매개변수를 제공합니다. 스트림의 모든 데이터가 처리된 후 지정된 값으로 트리거됩니다. 일반적인 접근 방식은 스트림의 종료 이벤트에서 콜백 함수를 정지하는 것입니다. , 그러나 처리되는 경우 함수는 시간이 많이 걸리는 비동기 작업이므로 모든 데이터가 처리되기 전에 콜백 함수가 호출될 수 있습니다.
'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'));
스트림의 종료 이벤트는 스트림의 데이터를 읽을 때만 트리거되기 때문에 모든 데이터가 처리되지 않은 경우 위 코드 콜백이 호출될 수 있습니다. 따라서 데이터가 처리되었는지 추가로 확인해야 합니다.
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() } }
이런 방식으로 모든 데이터가 처리된 후에 콜백이 실행됩니다.