I'd argue that few usages of async are motivated this way. In Rust land, it's efficiency and in JS land it's the browser scripting language legacy.
> cancelling tasks under the synchronous programming model requires passing a context object through every part of your code that might call down into an IO operation.
This is true for some but not all implementations. See eg Erlang or Unix processes (and maybe cancellation in pthreads?).
To be more precise, in JS land, we introduced async not directly because of scripting but because of backwards compatibility - prior to async/Promise, the JS + DOM semantics were specified with a single thread of execution in mind, with complex dependencies in both directions (e.g. some DOM operations can cause sync reflow while handling an event, which is... bad) and run-to-completion.
Promise made it easier to:
- cut monolithic chunks of code-that-needs-to-be-executed-to-completion-before-updating-the-screen into something that didn't cause jank;
- introduce background I/O.
async/await made Promise more readable.
(yes, that's for Promise and async/await on the browser, async callbacks have a different history on Node)
> cancelling tasks under the synchronous programming model requires passing a context object through every part of your code that might call down into an IO operation.
This is true for some but not all implementations. See eg Erlang or Unix processes (and maybe cancellation in pthreads?).