-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify that a pull source doesn't need to wait in pull() #1014
Comments
I don't think we should discourage returning a promise. Imagine a const rs = new ReadableStream({
async pull(c) {
await new Promise(r => setTimeout(r, 100));
c.enqueue('a');
c.enqueue('b');
}
}, { highWaterMark: 2 }); After Compare this to a version that does not return a promise: const rs = new ReadableStream({
pull(c) {
(async () => {
await new Promise(r => setTimeout(r, 100));
c.enqueue('a');
c.enqueue('b');
})();
}
}, { highWaterMark: 2 }); After This is probably a bit of a contrived example. But you could have a similar problem if you need to do some cleanup after each // imagine there's a hypothetical `source` somewhere
const rs = new ReadableStream({
pull(c) {
await source.startPulling();
const chunk = await source.getNextChunk();
c.enqueue(chunk);
await source.finishPulling();
}
}); By returning a promise, we ensure that Alternatively: could we pass an |
I didn't mean to discourage it, just to make clear that not returning a promise is an option. Maybe if I think about it a bit more I can come up with some concrete guidelines for when to do what. I don't know how I feel about abortable |
Yeah, I'm not sure about it either, just thinking out loud. The examples above are purely hypothetical, I haven't actually come across a real-world use case where Then again, passing an
|
I don't think this part is correct:
As far as I know, we don't actually wait for the pending var rs = new ReadableStream({
async pull(c) {
console.log("source pull");
await new Promise(r => setTimeout(r, 1000));
console.log("source enqueue");
c.enqueue("a");
console.log("source pull done");
},
cancel(reason) {
console.log("source cancel", reason);
}
}, { highWaterMark: 0 });
var reader = rs.getReader();
reader.read().then((result) => console.log("read", result));
setTimeout(() => reader.cancel("hi"), 100); This logs:
The source receives the
This also means my previous suggestion for passing an var rs = new ReadableStream({
start() {
this._controller = new AbortController();
},
async pull(c) {
const response = await fetch("./more/data/please", {
signal: this._controller.signal
});
const data = await response.json();
c.enqueue(data);
},
cancel(reason) {
this._controller.abort();
}
}, { highWaterMark: 0 }); |
I'm not sure what the source of my confusion was. We can probably close this. |
It's not just you. I even wrote code specifically to work around this "problem". But then I found that everything worked just fine without it, so I reverted it again. 😅 Moral of the story: test all your assumptions! 😁 I'm in favor of closing this. |
Maybe we should add an explicit note that |
When a source blocks inside
pull()
, it is not possible to cancel the ReadableStream until the promise returned bypull()
settles. In some casespull()
may never return.However, it is not necessary to block in
pull()
. In many (most?) cases, returning an already-resolved promise frompull()
and then enqueueing later to trigger the next call topull()
works fine.This should be clarified in the description of underlying source.
The text was updated successfully, but these errors were encountered: