-
Notifications
You must be signed in to change notification settings - Fork 34
Cancellation #162
Comments
can you elaborate more on this? in my mind you can "cancel" an iterator using .return/.throw. |
Sure, I was sitting with @ronag and @Ethan-Arrowhead in a conference and people are asking The use case we found is something like this: const iterable = obtainGeneratorOfUrls().map(async (url, { signal }) => {
await fetch(url, { signal }); // cancel the request
});
// fetch first two urls
iterable.next();
iterable.next();
// close the generator, usually break from the loop
iterable.return(); // I want this to abort ongoing `fetch` requests.
`` |
|
that is indeed an interesting use case and it seems well motivated to me. I'm not sure it could be neatly solved within the scope of this proposal though. |
@zloirock yes, that is a reasonable concern. It has been discussed a bunch before. There have been talks (in the cancellation proposal's protocol version and elsewhere) about specifying a way for the spec to interact with cancellable things (like AbortSignal). I think this can and will (eventually) be solved and the spec will be able to interact with Note that my understanding is that Chrome's opinion is that @devsnek the ask here isn't for this proposal to enable cancellation but to provide a future-proofing guarantee so that when this issue is resolved in TC39 a signal can be passed eventually. |
And we need to have |
I might be getting off-topic, but I am happy to discuss what it would include although I am hardly an expert. When talking to DOM people I think it should be sufficient to specify an That is considerably less work than specifying |
If you specify it in an incompatible way, it won't be added to the language. |
I am not sure what you mean by "an incompatible way" so I think I'm probably not explaining myself well. I am not suggesting specifying a primitive |
I think what @benjamingr is suggesting is that the aborting primitive would be host-defined. That could be a reasonable way forward here. I suspect that the web, Deno, and Node.js would all pick the same primitive, but other hosts might not. |
(See also tc39/proposal-cancellation#22 (comment). CC: @rbuckton, @ljharb, @domenic.) |
@js-choi thanks. I'd like to emphasize that I am very interested (both personally and as a Node.js member) in this proposal regardless of the language getting cancellation before/after. My ask here is much much smaller in scope and is only future compatibility for eventually supporting cancellation (e.g. pass a second argument to I am confident that can be done in an iterative approach (this proposal lands, a future proposal adds this capability) and I am only asking for that reasonable extension to be taken into account. |
I feel like the thing missing here is not support for cancellation, but rather support for cleanup. That is, suppose we had a class Iterator {
#cleanup = null;
cleanup(thunk) {
let old = this.#cleanup;
this.#cleanup = () => {
old?.call(this);
thunk.call(this);
return this;
};
}
return(arg) {
this.#cleanup?.();
return { value: arg, done: true };
}
throw(e) {
this.#cleanup?.();
throw e;
}
} Then you could do let controller = new AbortController();
const iterable = obtainGeneratorOfUrls().map(async url => {
await fetch(url, { signal: controller.signal });
}).cleanup(() => { controller.abort(); });
iterable.next();
iterable.next();
iterable.return(); But you could also do any other kind of cleanup you might need to do - release resources, etc - just as you'd do in a manually implemented [Edit: I guess [edit x2: opened #164 ] |
@benjamingr the problem is that chrome’s previously stated position is also that anything in the language using cancellation must have an AbortError that inherits from a DOMException, the latter of which doesn't belong in the language. If that changes, I’d be much more optimistic. Having the primitive be host-defined would be a step backwards; we’re trying to have fewer things be host-defined, not more. |
First, I'll second that I don't think cancelation support is a "v1" feature for proposal-iterator-helpers, i.e. it should not block stage advancement or anything like that. As we can see from some of the misunderstandings in this thread, it's a complex topic that needs its own discussion. It'd be good to ensure that the proposal is forward-compatible with cancelation. That seems relatively easy; e.g., the options argument sketch shown seems like something that could be added in a future proposal with no real compat concerns. So the proposal is probably already good from that perspective, although it might be good for the champions to double-check and keep that desire in mind through any future revisions that might happen. I don't think you need to explicitly pass an empty object as the second param to Finally, to expand on what @benjamingr and @annevk are saying, and some of the things mentioned in tc39/proposal-cancellation#22: the idea would be something like this.
The end result would be, as @annevk says, that various ES-defined APIs would accept You can imagine variants of this, e.g. if you don't want to tie yourself to the |
@ljharb - I am worried this is getting more and more off-topic but it's still interesting discussion. Maintainers of the repo - feel free to shut the discussion down and return it to the original discussion:
We are actually discussing using In particular my understanding of Domenic's "how this can be done with hooks" does not require If however there was a non DOMException AbortError standardized do you believe that would unblock all objections to language level support for the cancellation primitive? |
Correct, you would use HostGetAbortReason() which would return a host-specific value (usually an |
@benjamingr yes, notably, one that is in no way host-defined, including its prototype chain. |
I'm pretty sure that someone will make something like iterator.forEach(array.push.bind(array)) and in the future it will be impossible. |
If so that would have blocked many language changes; arrow functions are the preferred and more common way of passing callbacks of builtins (ie, the parseInt bug) |
How many new additional arguments were added to iteration methods? Moreover, to iteration methods that initially accept only 1 argument?
But |
"Someone might use it" isn't a strong argument against; "lots of people are likely to use it" can be.
|
@tabatkins even if one of the millions of developers will use |
Breaking the web isn't a binary state; one developer, one library, one site is definitely not necessarily enough. We have made many changes that technically "break the web" but don't actually do so. |
You've never been able to reliably use |
One more time,
|
However, why am I trying to explain this? That it will break the web, nothing will change personally for me. |
@benjamingr I'm not sure I understand the use case, is the requirement passing the signal (like this use case: tc39/proposal-function.sent#10 ) or |
@hax the requirement/ask for this proposal is to reserve the second parameter of methods like The actual use case is what .NET refers to "deep cancellation" - like: const urlRequests = AsyncIterator.from(urls).map((url, { signal }) => fetch(url, { signal }));
const request = urlRequests.next(); // get the next url response
urlRequests.return(); // close the iteration - this should abort the currently running url request |
I don't understand how could we reserve the second param for signals, the |
In those cases it'd be the third parameter - like what Node does.
It is auto-generated by the iterator and cancellation happens when the generator is disposed (by calling |
@benjamingr Thank you for the answer, now I feel I understand the case :-) |
Closing in favour of #164. |
Hey, @ronag and myself are looking at implementing this proposal (or a similar API) on Node.js streams and one thing we are missing is cancellation support.
Given the current state of things I think it would be useful to accept an options object as the second parameter (so we can pass an AbortSignal).
If this is complicated right now, it would be great if the spec was future-proofed for when cancellation has language level-support/integration.
Also - this is a good example of a language-level API that would benefit from cancellation at the language level.
The text was updated successfully, but these errors were encountered: