Is using async
and await
the crude person's threads?
Many moons ago I learned how to do multithreaded Java code on Android. I recall I had to create threads, start threads, etc.
Now I'm learning JavaScript, and I just learned about async
and await
.
For example:
async function isThisLikeTwoThreads() {
const a = slowFunction();
const b = fastFunction();
console.log(await a, await b);
}
This looks way simpler than what I used to do and is a lot more intuitive.
slowFunction()
would start first, then fastFunction()
would start, and console.log()
would wait until both functions resolved before logging - and slowFunction()
and fastFunction()
are potentially running at the same time. I expect it's ultimatly on the browser whether or not thesea are seperate threads. But it looks like it walks and talks like crude multithreading. Is it?
Is using
async
andawait
the crude person's threads?
No, not at all. It's just syntax sugar (really, really useful sugar) over using promises, which in turn is just a (really, really useful) formalized way to use callbacks. It's useful because you can wait asynchronously (without blocking the JavaScript main thread) for things that are, by nature, asynchronous (like HTTP requests).
If you need to use threads, use web workers, Node.js worker threads, or whatever multi-threading your environment provides. Per specification (nowadays), only a single thread at a time is allowed to work within a given JavaScript "realm" (very loosely: the global environment your code is running in and its associated objects, etc.) and so only a single thread at a time has access to the variables and such within that realm, but threads can cooperate via messaging (including transferring objects between them without making copies) and shared memory.
For example:
async function isThisLikeTwoThreads() { const a = slowFunction(); const b = fastFunction(); console.log(await a, await b); }
Here's what that code does when isThisLikeTwoThreads
is called:
slowFunction
is called synchronously and its return value is assigned to a
.fastFunction
is called synchronously and its return value is assigned to b
.isThisLikeTwoThreads
reaches await a
, it wraps a
in a promise (as though you did Promise.resolve(a)
) and returns a new promise (not that same one). Let's call the promise wrapped around a
"aPromise
" and the promise returned by the function "functionPromise
".aPromise
settles, if it was rejected functionPromise
is rejected with the same rejection reason and the following steps are skipped; if it was fulfilled, the next step is doneisThisLikeTwoThreads
continues by wrapping b
in a promise (bPromise
) and waiting for that to settlebPromise
settles, if it was rejected functionPromise
is rejected with the same rejection reason; if it was fulfilled, the code in isThisLikeTwoThreads
continues by logging the fulfillment values of aPromise
and bPromise
and then fulfilling functionPromise
with the value undefined
All of the work above was done on the JavaScript thread where the call to isThisLikeTwoThreads
was done, but it was spread out across multiple "jobs" (JavaScript terminology; the HTML spec calls them "tasks" and specifies a fair bit of detail for how they're handled on browsers). If slowFunction
or fastFunction
started an asynchronous process and returned a promise for that, that asynchronous process (for instance, an HTTP call the browser does) may have continued in parallel with the JavaScript thread while the JavaScript thread was doing other stuff or (if it was also JavaScript code on the main thread) may have competed for other work on the JavaScript thread (competed by adding jobs to the job queue and the thread processing them in a loop).
But using promises doesn't add threading. :-)