Uh oh!
There was an error while loading. Please reload this page.
stream: add a non-destroying iterator to Readable - #38526
Conversation
add a non-destroying iterator to Readable fixes: nodejs#38491
nodejs-github-bot
commented
May 4, 2021
mcollina
left a comment
There was a problem hiding this comment.
Good work! I've left a few notes.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| has less then 64KB of data because no `highWaterMark` option is provided to | ||
| [`fs.createReadStream()`][]. | ||
| ##### `readable.iterator([options])` |
There was a problem hiding this comment.
Just a thought: does this have to be in a new method rather than adding a parameter to the existing Symbol.asyncIterator one?
There was a problem hiding this comment.
I'm -0 on naming. I prefer a new method as the Symbol.asyncIterator one has a predefined signature by the standard.
There was a problem hiding this comment.
It doesn't feel right to me if the user has to call [Symbol.asyncIterator]() themselves.
There was a problem hiding this comment.
the
Symbol.asyncIteratorone has a predefined signature by the standard.
Not really, all the standard says it this method is called with no argument (https://tc39.es/ecma262/#sec-getiterator). The standard gives a clear rule for the returned object (https://tc39.es/ecma262/#sec-asynciterable-interface), but not for the function signature. I personally don't feel strongly either way.
There was a problem hiding this comment.
I'd prefer the separate method. The key issue with extending standard-defined APIs is that it makes reasoning about the portability of code far more complicated. A separate method makes it clear. That said, the behavior of the two can be identical such that [Symbol.asyncIterator]() could just defer to readable.iterator() with default arguments.
There was a problem hiding this comment.
That said, the behavior of the two can be identical such that
[Symbol.asyncIterator]()could just defer toreadable.iterator()with default arguments.
Yeah, the reason that one doesn't call the other is because of legacy streams and this. I'd need to use ReflectApply to bind this, and I preferred to have a regular method and send this as the first parameter instead of primordials.
nodejs-github-bot
commented
May 4, 2021
nodejs-github-bot
commented
May 6, 2021
Uh oh!
There was an error while loading. Please reload this page.
benjamingr
commented
May 6, 2021
I'm a bit torn about this because I think there is a good chance we picked the wrong default for |
mcollina
commented
May 6, 2021
I think the defaults are currently sound as the developer would need to do something to destroy the stream manually. The current defaults are safe. |
benjamingr
commented
May 6, 2021
So here are the two use cases I have: forawait(constchunkoffs.createReadStream('./foo')){// this should not leak}forawait(constchunkofsomeMethodReturningAStream()){// this should not leak}On the other hand, I want the following to also work: conststream=fs.createReadSream('./someFile');forawait(constchunkofstream){if(isSpecial(chunk))break;processFirst(chunk);// e.g. read http headers}forawait(constchunkofstream){// continues from where the last for await endedif(isOtherSpecial(chunk))break;processSecond(chunk);// e.g. read http body} |
One option would be to add a
conststream=fs.createReadStream('./someFile');stream.setIterationMode({destroyOnReturn: false,destoryOnError:false});forawait(constchunkofstream){if(isSpecial(chunk))break;processFirst(chunk);// e.g. read http headers}forawait(constchunkofstream){// continues from where the last for await endedif(isOtherSpecial(chunk))break;processSecond(chunk);// e.g. read http body} |
mcollina
commented
May 6, 2021
@benjamingr#38526 (comment) requirements are mutually exclusive. |
benjamingr
commented
May 7, 2021
That's sort of my point - it's the most concise way I could describe the problem. I'm not sure It's possible that this is the best we can do - I just think it's a difficult problem and I want to make sure we're not exploring too few options here. |
nodejs-github-bot
commented
May 7, 2021
mcollina
commented
May 7, 2021
How could it be on the stream? |
nodejs-github-bot
commented
May 12, 2021
Linkgoron
commented
May 12, 2021
@benjamingr Do you have any outstanding objections to this getting merged? |
benjamingr
commented
May 19, 2021
Nope, just uncertainty 😅 |
benjamingr
commented
May 19, 2021
I'd be more comfortable if this was experimental but I'm fine with this landing as stable. |
mcollina
commented
May 19, 2021
I'd be happy to land it doc-experimental if you prefer @benjamingr? No warnings and we do not backport. |
benjamingr
commented
May 19, 2021
doc-experimental is good to me. If others feel strongly that this is the right API I'd also happily concede. |
mcollina
commented
May 19, 2021
@Linkgoron can you add the experimental badge in there? |
Linkgoron
commented
May 22, 2021
Added the experimental tag in the method docs |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
jasnell
commented
May 25, 2021
Landed in df85d37 |
Add a non-destroying async iterator to Readable.
fixes: #38491
@nodejs/streams
A few things that I think might need attention:
createAsyncIteratormethod remove the listeners that it adds after the iteration ends? Currently it does not, but this was done when it essentially always destroyed the stream. Now it does not (although, it would be a bit problematic with Error, as it emits an error next-tick if an error was thrown). I'm not sure if it's that bad, as the listeners are mostly noops anyway.