From 3acf17d2a726a452cda15acde6631db0e6661e83 Mon Sep 17 00:00:00 2001 From: Andreas Lubbe Date: Mon, 8 Jun 2020 11:27:49 +0200 Subject: [PATCH] Support async iteration --- README.md | 8 +++++--- lib/iterateStream.js | 35 +++++++++++++++++++++++++++++++++++ unzip.js | 6 +++++- 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 lib/iterateStream.js diff --git a/README.md b/README.md index bf376e52..b965e3a8 100644 --- a/README.md +++ b/README.md @@ -77,16 +77,18 @@ fs.createReadStream('path/to/archive.zip') }); ``` -and the same example using async iterators: +and the same example using async iterators on node v12 and above: ```js const zip = fs.createReadStream('path/to/archive.zip').pipe(unzipper.Parse({forceStream: true})); -for await (const entry of zip) { +for await (const entry of unzipper.iterateStream(zip)) { const fileName = entry.path; const type = entry.type; // 'Directory' or 'File' const size = entry.vars.uncompressedSize; // There is also compressedSize; if (fileName === "this IS the file I'm looking for") { - entry.pipe(fs.createWriteStream('output/path')); + for await (const chunk of unzipper.iterateStream(entry)) { + console.log(chunk); + } } else { entry.autodrain(); } diff --git a/lib/iterateStream.js b/lib/iterateStream.js new file mode 100644 index 00000000..331cbe14 --- /dev/null +++ b/lib/iterateStream.js @@ -0,0 +1,35 @@ +const {once} = require('events'); + +module.exports = async function* iterateStream(stream) { + const contents = []; + stream.on('data', data => contents.push(data)); + + let resolveStreamEndedPromise; + const streamEndedPromise = new Promise(resolve => (resolveStreamEndedPromise = resolve)); + + let ended = false; + stream.on('end', () => { + ended = true; + resolveStreamEndedPromise(); + }); + + let error = false; + stream.on('error', err => { + error = err; + resolveStreamEndedPromise(); + }); + + while (!ended || contents.length > 0) { + if (contents.length === 0) { + stream.resume(); + // eslint-disable-next-line no-await-in-loop + await Promise.race([once(stream, 'data'), streamEndedPromise]); + } else { + stream.pause(); + const data = contents.shift(); + yield data; + } + if (error) throw error; + } + resolveStreamEndedPromise(); +}; diff --git a/unzip.js b/unzip.js index 07a8d811..fc795b72 100644 --- a/unzip.js +++ b/unzip.js @@ -8,4 +8,8 @@ require('setimmediate'); exports.Parse = require('./lib/parse'); exports.ParseOne = require('./lib/parseOne'); exports.Extract = require('./lib/extract'); -exports.Open = require('./lib/Open'); \ No newline at end of file +exports.Open = require('./lib/Open'); + +if (parseInt(process.versions.node.split('.')[0], 10) >= 12) { + exports.iterateStream = require('./lib/iterateStream'); +}