| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
add a non-destroying iterator to Readable fixes: nodejs#38491
Sorry, something went wrong.
There was a problem hiding this comment.
Good work! I've left a few notes.
Sorry, something went wrong.
| 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?
Sorry, something went wrong.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
It doesn't feel right to me if the user has to call [Symbol.asyncIterator]() themselves.
Sorry, something went wrong.
There was a problem hiding this comment.
the Symbol.asyncIterator one 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.
Sorry, something went wrong.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
That said, the behavior of the two can be identical such that [Symbol.asyncIterator]() could just defer to readable.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.
Sorry, something went wrong.
Sorry, something went wrong.
There was a problem hiding this comment.
lgtm
Sorry, something went wrong.
Sorry, something went wrong.
|
I'm a bit torn about this because I think there is a good chance we picked the wrong default for return on streams. I think pretty often people will need non-destructive iterators and for those cases having to write stream.iterator({ destroyOnReturn: false, destoryOnError:false }) isn't super ergonomic |
Sorry, something went wrong.
|
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. |
Sorry, something went wrong.
|
So here are the two use cases I have: for await(const chunk of fs.createReadStream('./foo')) { // this should not leak
}
for await(const chunk of someMethodReturningAStream()) { // this should not leak
}On the other hand, I want the following to also work: const stream = fs.createReadSream('./someFile');
for await(const chunk of stream) {
if (isSpecial(chunk)) break;
processFirst(chunk); // e.g. read http headers
}
for await(const chunk of stream) { // continues from where the last for await ended
if (isOtherSpecial(chunk)) break;
processSecond(chunk); // e.g. read http body
} |
Sorry, something went wrong.
One option would be to add a setIterationMode on Readable, where you could set the default type of iterator that Symbol.asyncIterator would return. Other options include stuff like having another alias for nonDestructive iterators (not a fan of having tons of aliases for the same method) or having iterator return with different defaults (which I don't think has much support here). setIterationMode would look something like this: const stream = fs.createReadStream('./someFile');
stream.setIterationMode({ destroyOnReturn: false, destoryOnError:false });
for await(const chunk of stream) {
if (isSpecial(chunk)) break;
processFirst(chunk); // e.g. read http headers
}
for await(const chunk of stream) { // continues from where the last for await ended
if (isOtherSpecial(chunk)) break;
processSecond(chunk); // e.g. read http body
} |
Sorry, something went wrong.
|
@benjamingr #38526 (comment) requirements are mutually exclusive. |
Sorry, something went wrong.
That's sort of my point - it's the most concise way I could describe the problem. I'm not sure .iterator is the best way to deal with it. I'm wondering if this should be on the stream rather than the iterator. 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. |
Sorry, something went wrong.
Sorry, something went wrong.
|
How could it be on the stream? |
Sorry, something went wrong.
Sorry, something went wrong.
|
@benjamingr Do you have any outstanding objections to this getting merged? |
Sorry, something went wrong.
|
Nope, just uncertainty 😅 |
Sorry, something went wrong.
|
I'd be more comfortable if this was experimental but I'm fine with this landing as stable. |
Sorry, something went wrong.
|
I'd be happy to land it doc-experimental if you prefer @benjamingr? No warnings and we do not backport. |
Sorry, something went wrong.
doc-experimental is good to me. If others feel strongly that this is the right API I'd also happily concede. |
Sorry, something went wrong.
|
@Linkgoron can you add the experimental badge in there? |
Sorry, something went wrong.
|
Added the experimental tag in the method docs |
Sorry, something went wrong.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Add a non-destroying async iterator to Readable.
fixes: #38491
@nodejs/streams
A few things that I think might need attention: