CAF
CAF copied to clipboard
add: capability inside a CAF function to do work exempt from cancellation-signal
This might seem quite contrary to CAF's design philosophy, which is that all async work should be cancelable. But, some async work is dependent on users, like prompting them for interactions -- even ones that go through browser prompts outside the control of the main UI thread -- which may not make sense to try to make dependent on cancellation signals (especially timeout based ones).
Here's one example use-case I've run into a few times now:
var whatever = CAF(function*whatever(signal){
var res = yield fetch("https://some.tld/api",{ signal });
var json = yield res.json();
renderResult(json);
// all done with the cancelable bits now, but some
// non-timeout-cancelable work left to do
yield showInfoNotice("Info updated");
});
// elsewhere:
await whatever(CAF.timeout(10_000,"took too long");
In this case, if the showInfoNotice() holds the whatever() task open indefinitely (waiting on user interaction, etc), it might cause the timeout signal to abort.
From an original design perspective, it'd be preferable if that non-timeout-cancelable work was split out into a separate non-CAF task. But whatever() can't invoke such a step, it would have to communicate that in some way back to the caller, perhaps returning a thunk the caller must detect and invoke.
The spirit of this is, sort of like a finally clause that runs after the CAF function has finished, and thus runs outside the purview of the cancellation signal.
I don't think I can actually detect a finally being used, so I don't think that works as an implementation option. But one way to do what I'm suggesting here might look like:
CAF(function*(signal){
// main work, subject to signal cancellation
CAF.finally(() => {
// do some post-cancellation-signal work
});
});
This has various pros/cons that need to be considered.
An alternative approach is to allow a signal to be "released" from inside the CAF function:
CAF(function*(signal){
// main work, subject to signal cancellation
// release this signal from CAF control for the rest
// of this function
signal.release();
// do some post-cancellation-signal work
});
I kind of like this approach better, but it also has its own downsides.
There might be other approaches I haven't thought of yet. Want this to simmer for a bit, see if anyone else has thoughts.