Async/await in TypeScript

Async/await in TypeScript

This article explains async/await in TypeScript.

YouTube Video

Async/await in TypeScript

In TypeScript, async is a keyword for concisely describing asynchronous operations and behaves similarly to JavaScript's async/await syntax. Async functions are designed to make handling functions that return Promises more intuitive.

Basics of async Functions

Functions declared with the async keyword always return a Promise. Here is a basic example:.

1async function fetchData(): Promise<string> {
2    return "Data received";
3}
4
5fetchData().then((data) => console.log(data)); // "Data received"

In this example, because the async function always returns a Promise, the returned value is automatically resolved using Promise.resolve. In other words, "Data received" becomes a Promise<string> and is treated as an asynchronous operation.

The await Keyword

The await keyword can only be used inside an async function. This provides the ability to pause and wait for the result of a Promise before continuing with the function execution.

In the following example, asynchronous processing using fetch is written with async/await.

 1async function getUserData() {
 2    try {
 3        const response = await fetch("https://codesparklab.com/json/example.json");
 4        const data = await response.json();
 5        console.log(data);
 6    } catch (error) {
 7        console.error("Error fetching user data:", error);
 8    }
 9}
10
11getUserData();

In this example, await is used to wait for the completion of the Promise returned by the fetch function, and its result is assigned to the variable response. Further, the result of response.json() is also awaited.

Error Handling with async/await

Errors that occur during asynchronous processing can be caught using the standard try...catch syntax. If an error occurs at the await part, that error is handled in the catch block.

 1async function fetchDataWithErrorHandling() {
 2    try {
 3        const response = await fetch('https://invalid.codesparklab.com/');
 4        if (!response.ok) {
 5            throw new Error(`HTTP error! status: ${response.status}`);
 6        }
 7        const data = await response.json();
 8        console.log(data);
 9    } catch (error) {
10        console.error("Fetch error:", error);
11    }
12}
13
14fetchDataWithErrorHandling();

In the above example, the result of the fetch function is awaited using await, and if an error occurs, it is handled with try...catch.

Advantages of async/await

  1. Intuitive asynchronous processing: By using async/await, the code flow is more intuitive than using Promise chains (then or catch), allowing it to be written like synchronous processing.

  2. Easy error handling: Using try...catch simplifies error handling in asynchronous operations. You can write more readable code than by using Promise chains.

Return Values of async Functions

An async function always returns a Promise. Therefore, even without explicitly returning a Promise, asynchronous processing is possible by using the async keyword.

1async function example() {
2    return 42;
3}
4
5example().then((result) => console.log(result)); // 42

In the code above, a synchronous value 42 is returned, but since it is inside an async function, it is automatically converted to Promise.resolve(42).

Sequential Execution of Asynchronous Functions

When executing multiple asynchronous functions in succession, you can use await to control their order.

 1async function fetchData(url: string): Promise<any> {
 2    try {
 3        const response = await fetch(url);
 4        return await response.json();
 5    } catch (error) {
 6        console.error("Error fetching user data:", error);
 7    }
 8}
 9
10async function fetchData1(): Promise<any> {
11    return await fetchData("https://codesparklab.com/json/example.json");
12}
13
14async function fetchData2(): Promise<any> {
15    return await fetchData("https://codesparklab.com/json/example2.json");
16}
17
18async function processData() {
19    const data1 = await fetchData1();
20    console.log(data1);
21
22    const data2 = await fetchData2();
23    console.log(data2);
24}
25
26processData();

In this example, fetchData2 is executed after waiting for fetchData1 to complete. This is more readable compared to using a Promise chain.

Parallel Execution

If you want to execute asynchronous operations in parallel, you can use Promise.all to handle multiple Promises simultaneously.

 1async function fetchData(url: string): Promise<any> {
 2    try {
 3        const response = await fetch(url);
 4        return await response.json();
 5    } catch (error) {
 6        console.error("Error fetching user data:", error);
 7    }
 8}
 9
10async function fetchData1(): Promise<any> {
11    return await fetchData("https://codesparklab.com/json/example.json");
12}
13
14async function fetchData2(): Promise<any> {
15    return await fetchData("https://codesparklab.com/json/example2.json");
16}
17
18async function fetchMultipleData() {
19    const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
20    console.log(data1);
21    console.log(data2);
22}
23
24fetchMultipleData();

In this case, fetchData1 and fetchData2 are executed at the same time, and the process proceeds after both are resolved. This allows for efficient handling of multiple asynchronous operations.

Summary

  • An async function returns a Promise, and by using the await keyword, you can wait for the result of an asynchronous operation.
  • By using try...catch, error handling in asynchronous operations becomes simpler.
  • By using Promise.all, it is possible to execute multiple asynchronous operations in parallel.

async/await is widely used in TypeScript and JavaScript because it allows for simpler description of asynchronous operations.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video