10:19 | <littledan> | If we seriously have extra time on the agenda, there are a couple wild open discussion topics which might be fun. Emoji-react something if you're interested in them. (Apologies for not raising this before the agenda deadline.) |
10:19 | <littledan> | Cancellable promises |
10:20 | <littledan> | Private name declarations outside of classes |
10:34 | <rbuckton> | Cancellable promises |
10:37 | <littledan> | Would it make sense to discuss this on https://github.com/tc39/proposal-cancellation? |
10:37 | <littledan> | also AbortSignal.any is a very helpful, core capability in this area, which I don't think was there last time we discussed this |
10:40 | <littledan> | (I guess it basically enables what your previous proposal's new CancellationTokenSource(linkedTokens?) does, roughly) |
10:46 | <rbuckton> | Unfortunately, since AbortSignal is outside the purview of TC39 the best forum for that may be WHATWG. |
10:47 | <rbuckton> | Though I've long held that cancellation graphs like that are very valuable |
10:47 | <littledan> | We'll definitely have to collaborate between standards groups to make this happen, but I think you were right to bring this to TC39, and believe we can make some progress together. |
10:49 | <littledan> | also if we want integration with async/await (e.g., all awaits are implicitly racing with the cancel token), something would need to happen in TC39 |
10:50 | <rbuckton> | I also agree that AsyncContext would have been the way to traffic a cancellation token in the way Yehuda wanted, so long as there was a way to suppress async context flow when needed |
10:50 | <littledan> | I also agree that AsyncContext would have been the way to traffic a cancellation token in the way Yehuda wanted, so long as there was a way to suppress async context flow when needed |
10:50 | <littledan> | I mean, requirements for it |
10:50 | <rbuckton> | The only avenue given to us at this point is a host hook. |
10:51 | <littledan> | IIRC wanting the cancel token to be implicitly propagated was a goal of Domenic's as well |
10:51 | <rbuckton> | could you say more about this suppression use case? |
10:51 | <rbuckton> | I have to step away, I'll discuss more shortly. |
10:52 | <littledan> | The only avenue given to us at this point is a host hook. |
11:02 | <rbuckton> | With the token as a parameter, it is up to the caller to determine whether to pass the token to a function. If you had a function that invoked a REST API, you might want to allow it to be cancellable in some cases, but not others. If there is no suppression mechanism, then there is no way for the caller to make this determination. The structure of the Cancellation API (so far as that proposal was concerned) ensured an appropriate separation of concerns so that the correct level of control was available with respect to the caller and the call site. |
11:10 | <rbuckton> | (I guess it basically enables what your previous proposal's |
11:11 | <littledan> | With the token as a parameter, it is up to the caller to determine whether to pass the token to a function. If you had a function that invoked a REST API, you might want to allow it to be cancellable in some cases, but not others. If there is no suppression mechanism, then there is no way for the caller to make this determination. The structure of the Cancellation API (so far as that proposal was concerned) ensured an appropriate separation of concerns so that the correct level of control was available with respect to the caller and the call site. |
11:11 | <littledan> | One of the major reasons I wanted a linked cancellation graph was to address memory overhead. If cancellation sources could be intrinsically linked, and could be disposed when cancellation was no longer needed, then all of the token subscriptions could be GC'd (incl. the callbacks and closed-over variables that they held). |
11:11 | <rbuckton> | A fresh token, or no token. |
11:11 | <rbuckton> | I would have to think about that. IIRC, the issue with any is how ownership is controlled for a subgraph. |
11:12 | <littledan> | I would have to think about that. IIRC, the issue with any has to be used in a sort of opinionated way to make things work |
11:12 | <littledan> | and your proposed signature sort of already encapsulates that pattern |
11:13 | <rbuckton> | Let's say I receive a token and want to call another function with both that and my own token. With any , I can close my source, but since I have no control over the incoming token, the graph can't be GC'd |
11:14 | <littledan> | which graph do you mean? |
11:16 | <rbuckton> |
|
11:17 | <rbuckton> | Here, even if we think inner should keep going, if signal is canceled then combinedSignal is cancelled. |
11:18 | <rbuckton> | If any returns a signal, then I can't model this relationship using it. |
11:19 | <rbuckton> | But if
|
11:21 | <rbuckton> | The new CancellationTokenSource(linkedTokens?) API allowed you to express this relationship. If you need control over the subgraph, you hold a reference to the source. If you don't need control over the subgraph, you don't hold a reference to the source and just pass along it's token . |
11:21 | <littledan> | Btw did you point this out in any issue on the AbortSignal.any repo? |
11:22 | <rbuckton> | I wasn't aware of an AbortSignal.any repo, but I've definitely discussed it many years ago in TC39 as part of the cancellation proposal. |
11:23 | <littledan> | This was the repo, but it's already shipping across browsers https://github.com/shaseley/abort-signal-any |
11:24 | <littledan> | I had trouble following all the aspects of your previous presentation, and was watching this proposal later, and thought it was good and solved the problems you were raising. |
11:26 | <rbuckton> | Ah, that's unfortunate. |
11:26 | <littledan> | I have trouble tracing the leak in the above code. It's that it's less apparent that the controller is dead? |
11:26 | <rbuckton> | No, the problem is that the controller isn't dead in the first example. |
11:27 | <littledan> | sure, that it isn't dead, so how big of a leak is that? |
11:27 | <littledan> | it's only referred to by that local variable, and that can be collected once you leave the scope. or is there anything else? |
11:28 | <littledan> | (I thought solving this particular GC issue was like 80% of the point of AbortSignal.any in the first place) |
11:28 | <rbuckton> | It's not a leak, it's bigger than that. If I wanted to be able to control whether inner could even be cancelled anymore after a certain point, I would not be able to do so in that approach, so it actually affects capabilities, not just memory. |
11:29 | <rbuckton> | Also, if there is no dispose() /close() then you're not addressing the GC concern at all. |
11:29 | <littledan> | how can you do that with the API you're proposing? |
11:29 | <rbuckton> | It's quite hard to explain in text without drawing a graph :/ |
11:57 | <rbuckton> | Lets assume for a moment that an
My algorithm reaches a point of no return where I no longer want |
12:03 | <rbuckton> | In the
|
12:08 | <rbuckton> | So the difference between the two designs is not just one of memory efficiency, but capability. b(a) has a capability that ab does not. |
12:27 | <rbuckton> | I also discuss a lot of this in https://github.com/tc39/proposal-cancellation/blob/master/stage0/README.md, which was pulled out of the explainer when it advanced to stage 1. |
14:52 | <littledan> | I don't see anything in these docs about disposal. Is disposal really a necessary feature? |
14:57 | <littledan> | There's some related discussion about being on AbortController vs AbortSignal in https://github.com/shaseley/abort-signal-any/#exposure-through-abortsignal-vs-abortcontroller |
17:03 | <rbuckton> | I don't see anything in these docs about disposal. Is disposal really a necessary feature? source.close() in that stage 0 explainer. I believe it is important, and the lack of it today is wasteful. |
17:09 | <rbuckton (traveling)> | https://github.com/tc39/proposal-cancellation/blob/master/stage0%2FREADME.md#sourceclose |
17:17 | <rbuckton (traveling)> | If you can close/dispose a source, functions that receive the closed token can use more efficenct code paths, and registrations that would have introduced closures can be skipped. A source that is left open instead of canceling/closing results in closures holding references to closed over values far longer than necessary. IIRC, AbortSignal doesn't even clean up user code registrations when aborted since user code registrations are event based |
17:28 | <rbuckton (traveling)> | FYI, the most recent iteration of this API is here: https://esfx.js.org/esfx/api/canceltoken.html?tabs=ts |
17:31 | <rbuckton (traveling)> | Where CancelToken.race(cancelables) is the same as AbortSignal.any , but CancelToken.source(cancelables) is preferred. |
22:00 | <littledan> | See |