This is part of Academy's technical curriculum for The Mark. All parts of that curriculum, including this project, are licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Having looked at Promises - one way of writing asynchronous code in JS/TS - we'll now look at async
/await
, which is another way of writing asynchronous code (but in a way that feels synchronous).
- Declare an
async
function expression - Explain the blocking role of
await
- Declare an
async
arrow function
🎯 Success criterion: You can declare an
async
function and explain the blocking role ofawait
Demo 1 has three function expressions declared - all of which are preceded with async
, which makes them async
functions.
However, async
functions work pretty similarly to traditional (synchronous) functions.
Run the demo for printStraightforwardly
. You'll see the output is exactly what you would see without the async
keyword being there.
In fact, you can remove the async
keyword and re-run the demo, and the output will be identical.
The same is true if you were to run printWithSleepNoBlock
(and comment out the printStraightforwardly
execution) - with, or without, the async
keyword. sleep(5000)
creates a promise that takes 5 seconds to resolve, but it's non-blocking, so the following console.log
s can go ahead as before.
printWithSleepAndBlock
is different.
De-comment the printWithSleepAndBlock("Hello world!")
execution (and comment out printStraightforwardly
and printWithSleepNoBlock
), and then run it.
What you'll see is that our default non-blocking behaviour of promises has changed. Now, the execution of the function body pauses at sleep(5000)
until its promise resolves - and then, once the promise has resolved, the function continues with the rest of its body.
Unlike the earlier functions in the demo, you can't remove the async
keyword before printWithSleepAndBlock
. If you try (and you should), TypeScript will warn you:
'await' expressions are only allowed within async functions and at the top levels of modules.
Both .then
and async
/await
are accepted modern ways of writing asynchronous JS/TS (which also are not mutually exclusive - they can be used together).
The non-blocking behaviour of .then
lets you just get on with other things whilst you're waiting for some asynchronous operation to complete.
On the other hand, a lot of people find async
/await
easier to reason about - because it looks a lot more like normal synchronous code, where one line only runs after the previous line has been completed.
🎯 Success criterion: You can type the return value of a simple
async
function expression
We've seen that making a function async
lets us use the await
keyword for if we want to block until a promise is resolved, and it didn't seem to do very much to a function otherwise.
However, even if we don't use await
inside a function, adding async
does do something - it changes the return type of a function.
Any async
function must return a Promise<T>
for some resolve value type T
:
Promise<void>
is possiblevoid
is not possiblePromise<string>
is possiblestring
is not possible
This means that you could, in principle, chain a .then
after you call an async
function, since all Promises have a .then
method.
You can experiment with this in the src/1-async-return.ts
file.
Try adding explicit return value types to functions like this:
async function promiseToAdd(a: number, b: number) {
return a + b;
}
🎯 Success criterion: You can distinguish the types of
Promise<T>
and type ofawait Promise<T>
As we've seen, Promises can be typed with a specific resolve value: Promise<T>
indicates that the Promise will resolve with a type of T
.
When you await Promise<T>
, we block future execution until the promise resolves - and, if it resolves with a value, then the await
expression returns that value.
You can see this in demo 2 by inspecting:
- the type of
promiseOne
- the type of
resultOne
- the type of
resultTwo
- the return type of
unfurlDemo
🎯 Success criterion: You can declare an
async
arrow function
Demo 3 shows how an async
arrow function can be defined - similar to function expressions, it involves an extra async
keyword and wraps up the return value into a Promise.