- Version: v10.12.0
- Platform: Windows 10 64-bits
- Subsystem: streams
Async iteration over a readable stream breaks horribly if for any reason the stream is destroyed while the iteration is still running (or even if it is destroyed before starting the iteration). I would expect that the iteration runs normally or throws an exception. What happens instead is that the whole event loop is shut down.
Most notably this makes async iteration useless with pipeline.
Test code:
const{createReadStream}=require('fs');const{pipeline}=require('stream');const{createDeflate}=require('zlib');asyncfunctioniterate(name,stream,destroy=false){try{console.log(`${name}: Starting loop`);forawait(constchunkofstream){console.log(`${name}: Got a chunk`);if(destroy){console.log(`${name}: destroying stream`);stream.destroy();}}console.log(`${name}: loop ended`);}catch(err){console.log(`${name}: loop ended with error: ${err}`);}}asyncfunctionmain(){// These work fineawaititerate('oneStream',createReadStream('test.js'));awaititerate('oneStreamError',createReadStream('doesnotexist'));// Any of these just shuts down the node event loop...awaititerate('oneStreamDestroy',createReadStream('test.js'),true);awaititerate('pipeline',pipeline(createReadStream('doesnotexist'),createDeflate(),err=>console.log(`pipeline ended: ${err}`)));conststream=createReadStream('test.js');stream.destroy();awaititerate('destroyedStream',stream);}main().catch(console.error);Output:
> node test.js
oneStream: Starting loop
(node:21664) ExperimentalWarning: Readable[Symbol.asyncIterator] is an experimental feature. This feature could change at any time
oneStream: Got a chunk
oneStream: loop ended
oneStreamError: Starting loop
oneStreamError: loop ended with error: Error: ENOENT: no such file or directory, open 'C:\Users\mfischer\src\tests\node-stream-async-iteration\doesnotexist'
oneStreamDestroy: Starting loop
oneStreamDestroy: Got a chunk
oneStreamDestroy: destroying stream
Async iteration over a readable stream breaks horribly if for any reason the stream is destroyed while the iteration is still running (or even if it is destroyed before starting the iteration). I would expect that the iteration runs normally or throws an exception. What happens instead is that the whole event loop is shut down.
Most notably this makes async iteration useless with
pipeline.Test code:
Output: