Understanding Async/Await in JavaScript
Async/await lets you write async code in a way that looks like sync code. You can
use if
statements, for
loops, and try/catch
in async functions!
Async
The async
keyword marks a function as an async function. In the below example, test()
is an
async function.
async function test() {
return 42;
}
You can also define an async arrow function:
const test = async () => 42;
Await
The special thing about async functions is that you can use the await
keyword. If you await
on a promise, the await
keyword pauses execution of
the surrounding async function until the promise fulfills or rejects. await
also unwraps the promise: it
gives you the fulfilled value of the promise.
async function test() {
// `await` unwraps the promise's value
const val = await Promise.resolve(42);
val; // 42
}
test();
In the above example, the Promise.resolve()
function means the promise is fulfilled immediately. In the below example,
await
pauses execution of test()
for 100 ms:
`
async function test() {
const start = Date.now();
await new Promise(resolve => setTimeout(resolve, 100));
const elapsed = Date.now() - start;
elapsed; // about 100
}
await
is just a plain old JavaScript keyword. That means you can use it within
if
statements, for
loops, and try/catch
.
async function asyncEvenNumbers() {
const nums = [];
for (let i = 1; i <= 10; ++i) {
if (i % 2 === 0) {
const v = await Promise.resolve(i);
nums.push(v);
}
}
nums; // [2, 4, 6, 8, 10]
}
Return Value
Another special property of async functions is that they always return a promise. Even if you return a primitive value from an async function, JavaScript will wrap that value in a promise.
async function test() {
return 42;
}
const p = test();
p instanceof Promise; // true
p.then(v => {
v; // 42
});
That means can use await
on an async function call:
async function test() {
return 42;
}
async function main() {
const val = await test();
val; // 42
}
Error Handling
Error handling with async/await is a complex topic. But, at a high level, there are two patterns for handling errors.
When you await
on a promise and that promise rejects, await
throws an
error that you can try/catch
:
async function test() {
try {
await Promise.reject(new Error('Oops'));
} catch (err) {
err.message; // Oops
}
}
You can also use the Promise#catch()
function to unwrap the promise's error:
async function test() {
const promise = Promise.reject(new Error('Oops'));
// Unwrap the promise's error
const err = await promise.catch(err => err);
err.message; // 'Oops'
}