Async/await in JavaScript
In this article, we will explain async/await in JavaScript.
YouTube Video
Async/await in JavaScript
async
(and await
) in JavaScript are features designed to make writing asynchronous operations more intuitive and readable. By using this, you can reduce the complexity of traditional callback functions and Promise
chains, and write asynchronous code in a way that looks like synchronous code.
async
Function
async
is used to define a function as an asynchronous function. An async
function always returns a Promise. Within a function marked with async
, you can use await
to wait for the result of a Promise to be returned.
Basic Syntax of an async
Function
1async function myAsyncFunction() {
2 // Write asynchronous processing here
3 return 'Result'; // Return a Promise
4}
In this case, calling myAsyncFunction()
automatically returns a Promise object. When the Promise is resolved, its result becomes the value returned by return
.
Example: Basic async
Function
1async function greet() {
2 return 'Hello, World!';
3}
4
5greet().then((message) => {
6 console.log(message); // Displays "Hello, World!"
7});
await
await
is used to wait for a Promise to be resolved. By using await
, you can pause the execution until the Promise is resolved and receive the result of the Promise. await
can only be used inside an async
function.
Example: How to Use await
1async function fetchData() {
2 // Wait for the result of the Promise
3 const data = await fetch('https://codesparklab.com/json/example.json');
4 // Wait for the asynchronous operation to complete
5 const jsonData = await data.json();
6 // Retrieve and display the data
7 console.log(jsonData);
8}
9
10fetchData();
In the example above, it waits for the Promise returned by the fetch
function with await
, and then performs further asynchronous operations using the result.
Error Handling with async
/await
If an error occurs inside an async
function, that error is treated as a reject
of the Promise. You can use try...catch
statements to perform error handling.
Example: Error Handling
1async function fetchData() {
2 try {
3 // Invalid URL
4 const data = await fetch('https://invalid.codesparklab.com/');
5 const jsonData = await data.json();
6 console.log(jsonData);
7 } catch (error) {
8 // Catch the error
9 console.error('Failed to fetch data:', error);
10 }
11}
12
13fetchData();
Using a try...catch
block allows you to catch errors that occur during asynchronous operations, preventing the program from crashing when errors occur.
Benefits of async
/await
Compared to traditional Promise
chains, async
/await
offers the following advantages:.
- Improved readability
- Asynchronous processing can be written like synchronous code, avoiding the complexity of deeply nested
Promise
chains and callbacks.
- Asynchronous processing can be written like synchronous code, avoiding the complexity of deeply nested
- Easier debugging
- Since it resembles synchronous code, debugging and error handling become easier.
- Better maintainability
- Asynchronous processes can be written more simply, making it easier to change or modify the code and improving long-term maintainability.
Example: Promise
chain vs async
/await
Let’s compare code using Promise
chains and code using async
/await
.
1// Code using Promise chains
2function fetchDataPromise() {
3 fetch('https://codesparklab.com/json/example.json')
4 .then((response) => response.json())
5 .then((data) => {
6 console.log(data);
7 })
8 .catch((error) => {
9 console.error('Failed to fetch data:', error);
10 });
11}
12
13// Code using async/await
14async function fetchDataAsync() {
15 try {
16 const response = await fetch('https://codesparklab.com/json/example.json');
17 const data = await response.json();
18 console.log(data);
19 } catch (error) {
20 console.error('Failed to fetch data:', error);
21 }
22}
As you can see, using async
/await
allows you to write asynchronous processes in a linear fashion, resulting in more readable code.
Execute multiple asynchronous operations simultaneously
By combining Promise.all()
or Promise.race()
with await
, you can execute multiple asynchronous operations simultaneously and handle their results collectively.
Promise.all()
1async function fetchMultipleData() {
2 try {
3 const [data1, data2] = await Promise.all([
4 fetch('https://codesparklab.com/json/example1.json'),
5 fetch('https://codesparklab.com/json/example2.json')
6 ]);
7 const jsonData1 = await data1.json();
8 const jsonData2 = await data2.json();
9 console.log(jsonData1);
10 console.log(jsonData2);
11 } catch (error) {
12 console.error('Failed to fetch data:', error);
13 }
14}
15
16fetchMultipleData();
Promise.all()
resolves multiple Promises simultaneously and returns their results as an array. It waits for all Promises to be resolved, and if any of them fail, it is considered a failure overall.
Promise.race()
1async function fetchFastestData() {
2 try {
3 const fastestResponse = await Promise.race([
4 fetch('https://codesparklab.com/json/example1.json'),
5 fetch('https://codesparklab.com/json/example2.json')
6 ]);
7 const jsonData = await fastestResponse.json();
8 console.log('Fastest data:', jsonData);
9 } catch (error) {
10 console.error('Fetch error:', error);
11 }
12}
13
14fetchFastestData();
Promise.race()
returns the result of the first Promise that is either fulfilled or rejected. It is useful when you want to respond to whichever asynchronous operation completes first. However, if the first Promise fails, the error is immediately caught bycatch
.
Promise.allSettled()
1async function fetchWithAllSettled() {
2 const results = await Promise.allSettled([
3 // This URL will success
4 fetch('https://codesparklab.com/json/example1.json'),
5 // This URL will fail
6 fetch('https://invalid.codesparklab.com/')
7 ]);
8
9 results.forEach((result, index) => {
10 if (result.status === 'fulfilled') {
11 const url = result.value.url;
12 console.log(`Request ${index + 1} succeeded:`, url);
13 } else {
14 const reason = result.reason;
15 console.warn(`Request ${index + 1} failed:`, reason);
16 }
17 });
18}
19
20fetchWithAllSettled();
Promise.allSettled()
waits for all results, regardless of success or failure. Each result is returned in the form of{ status, value }
or{ status, reason }
, allowing you to determine which Promises succeeded and which failed.
Promise.any()
1async function fetchAnySuccessful() {
2 try {
3 const firstSuccessful = await Promise.any([
4 // This URL will fail
5 fetch('https://invalid.codesparklab.com/'),
6 // This URL will success
7 fetch('https://codesparklab.com/json/example1.json')
8 ]);
9 const jsonData = await firstSuccessful.json();
10 console.log('First successful response:', jsonData);
11 } catch (error) {
12 console.error('All fetch requests failed:', error);
13 }
14}
15
16fetchAnySuccessful();
Promise.any()
returns only the result of the first successfully fulfilled Promise. An exception is thrown only if all Promises fail. It can be used like a retry mechanism in environments where some APIs are unreliable until one succeeds.
Summary
async
function: Always returns a Promise and is used to write asynchronous processing.await
: Used to wait for a Promise to resolve and receive its result.- Error handling: Use
try...catch
to handle errors that occur during asynchronous processing. - Multiple asynchronous operations: By using methods like
Promise.all()
, you can run multiple asynchronous tasks concurrently.
async
/await
are powerful tools for handling asynchronous processing, so be sure to utilize them to simplify complex asynchronous logic.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.