- Learning TypeScript 2.x
- Remo H. Jansen
- 480字
- 2025-04-04 17:02:05
Asynchronous functions – async and await
Asynchronous functions are a TypeScript feature that arrived with the TypeScript 1.6 release. Developers can use the await keyword to wait for the function results without blocking the normal execution of the program.
Using asynchronous functions helps to increase the readability of a piece of code when compared with the use of promises or callbacks, but technically, we can achieve the same features using both promises and synchronous code.
Let's take a look at a basic async/await example:
let p = Promise.resolve(3); async function fn(): Promise<number> { let i = await p; // 3 return 1 + i; // 4 } fn().then((r) => console.log(r)); // 4
The preceding code snippet declares a promise named p. This promise is the piece of code whose execution we will wait for. While waiting, the program execution will not be blocked because JavaScript allows us to wait for an asynchronous function named fn without blocking it. As we can see, the fn function is preceded by the async keyword, which is used to indicate to the compiler that it is an asynchronous function.
Inside the function, the await keyword is used to suspend execution until the promise p is fulfilled or rejected. As we can see, the syntax is less verbose and cleaner than it would have been if we used the promises API or callbacks.
The fn function returns a promise at runtime because it is an async function. This should explain why we need to use the then callback to invoke it at the end of the code snippet.
The following code snippet showcases how we can declare an asynchronous function named invokeTaskAsync. The asynchronous function uses the await keyword to wait for the result of the doSomethingAsync, doSomethingElseAsync, and doSomethingMoreAsync functions that we declared during the promises example:
async function invokeTaskAsync() { let arr1 = await doSomethingAsync([]); let arr2 = await doSomethingElseAsync(arr1); return await doSomethingMoreAsync(arr2); }
The invokeTaskAsync function is asynchronous, and therefore, it will return a promise at runtime. This means that we can use the promises API to await a result or catch potential errors respectively:
invokeTaskAsync().then((result) => { console.log( ` doSomethingAsync: ${result[0]} doSomethingElseAsync: ${result[1]} doSomethingMoreAsync: ${result[2]} ` ); }).catch((e) => { console.log(e); });
We can also define asynchronous IIFE as a convenient way to use the async and await keywords:
(async () => { try { let arr1 = await doSomethingAsync([]); let arr2 = await doSomethingElseAsync(arr1); let arr3 = await doSomethingMoreAsync(arr2); console.log( ` doSomethingAsync: ${arr3[0]} doSomethingElseAsync: ${arr3[1]} doSomethingMoreAsync: ${arr3[2]} ` ); } catch (e) { console.log(e); } })();
Using an async IIFE is very useful because it is very common to not be able to use the await keyword outside of a function—for example, in the entry point of an application. We can use the async IIFE to overcome this limitation:
(async () => { await main(); })();