Asynchronous programming in TypeScript has been greatly simplified with the introduction of async/await
functions
Asynchronous programming in TypeScript has been greatly simplified with the introduction of async/await
functions. While async/await
makes code look synchronous, really knowing how it works gives us power to use it to its fullest.
In this article, we’ll dive into asynchronous functions, exploring their syntax, return types, and advanced usage using examples encountered on my project.
Understanding Basic Asynchronous Function Syntax
At its core, an async
function is marked by the async
keyword, signaling its asynchronous nature. Even when seemingly returning synchronously, the function inherently returns a Promise:
async function fetchData() {
return 'data';
}
// Inferred return type: Promise<string>
This minimal example sets the stage for the async/await
journey.
Unwrapping Values with Await
One of the defining features of async/await
is the await
keyword, which retrieves the resolved value of a Promise. Consider the following example fetching data from database:
async function GetDataByDate(date: Date) {
const order = await DataService.getOrderByDate({ date });
const contracts = await DataService.getContractByDate({ date });
return { order, contracts };
}
Here, we call the getOrderByDate
method and getContractByDate
of the dataService
with a specific date
parameter and returns the fetched data.
Resolving Promises
While await
unwraps the resolved value of a Promise, it's important to understand how to create and return resolved Promises explicitly. The Promise.resolve
method facilitates this:
async function getOrderByDate(date: Date) {
const resolvedValue = await Promise.resolve({
date: new Date(2023, 10, 23),
orderedQuantity: 100000
});
return resolvedValue;
}
This function utilizes Promise.resolve
to create and resolve a Promise.
Handling Rejections and Promise Never Types
In the realm of async/await
, handling errors is important. If an await
encounters a rejected Promise, it throws an error. The return type, in this case, is inferred as Promise<never>
:
async function getContractByDate(date: Date) {
const rejectedValue = await Promise.reject('Unexpected error happened during getting contract.');
return rejectedValue;
}
Leveraging Promise Utility Methods
async
functions harmonize seamlessly with Promise utility methods like Promise.all
. This enables parallel execution without altering the function's behavior:
type DataByDate = {
order: OrderByDate;
contract: ContractType;
};
async function GetDataByDate(date : Date) : Promise<DataByDate> {
try {
// Use Promise.all to concurrently fetch order and contract
const [order, contract] = await Promise.all([
DataService.getOrderByDate(date),
DataService.getContractByDate(date),
]);
return { order, contract };
} catch (error) {
throw error; // throw the error
}
}
This example showcases the ability to utilize Promise utility functions to enhance the efficiency of asynchronous code.
Conclusion
async/await
in TypeScript is not just a syntax feature; it’s a paradigm shift that empowers developers to write more expressive, readable, and efficient asynchronous code. So, let’s continue leveraging the advantages of async/await
to build robust, scalable, and future-ready applications.
Thank you.