Ts Async Await
## TypeScript async/await: Asynchronous Programming
`async/await` is a syntax sugar introduced in ES2017 (and fully supported in TypeScript) that makes asynchronous code look and behave more like synchronous code. It is built on top of Promises, providing a cleaner, more readable, and easier-to-maintain alternative to traditional callback chains and `.then()` promise chains.
---
## Understanding async/await
To master asynchronous programming in TypeScript, it is essential to understand the roles of these two keywords:
* **`async`**: Used to declare an asynchronous function. An `async` function always returns a `Promise`. If the function returns a value directly, TypeScript automatically wraps it in a resolved Promise.
* **`await`**: Can only be used inside an `async` function. It pauses the execution of the function, waiting for the specified Promise to resolve or reject, and then resumes execution with the resolved value.
---
## Syntax and Usage
### The `async` Keyword
When you mark a function with `async`, its return type is implicitly or explicitly wrapped in a `Promise`.
```typescript
// A simple async function returning a string
async function greet(): Promise {
return "Hello, YouTip!";
}
greet().then(message => console.log(message)); // Outputs: Hello, YouTip!
```
### The `await` Keyword
The `await` keyword pauses the execution of the surrounding `async` function until the awaited Promise settles (resolves or rejects).
```typescript
// A function that simulates an API call returning a Promise
function fetchUserData(): Promise<{ id: number; name: string }> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 1, name: "Alice" });
}, 1000);
});
}
// Using await to retrieve the resolved value
async function displayUser() {
console.log("Fetching user...");
const user = await fetchUserData(); // Pauses here until fetchUserData resolves
console.log(`User loaded: ${user.name}`);
}
displayUser();
```
---
## Comprehensive Code Examples
### 1. Sequential vs. Parallel Execution
When dealing with multiple asynchronous operations, you can choose to run them sequentially (one after another) or in parallel (simultaneously) to optimize performance.
```typescript
function delay(ms: number, value: string): Promise {
return new Promise(resolve => setTimeout(() => resolve(value), ms));
}
// Sequential Execution: Takes ~3 seconds in total
async function runSequentially() {
console.time("Sequential");
const result1 = await delay(1500, "First Task");
const result2 = await delay(1500, "Second Task");
console.log(result1, result2);
console.timeEnd("Sequential");
}
// Parallel Execution using Promise.all: Takes ~1.5 seconds in total
async function runInParallel() {
console.time("Parallel");
const promise1 = delay(1500, "First Task");
const promise2 = delay(1500, "Second Task");
// Wait for both promises to resolve concurrently
const [result1, result2] = await Promise.all([promise1, promise2]);
console.log(result1, result2);
console.timeEnd("Parallel");
}
runSequentially().then(() => runInParallel());
```
### 2. Error Handling with `try...catch`
In synchronous code, we use `try...catch` blocks to handle errors. With `async/await`, you can use the exact same structure to handle asynchronous rejections, making error handling highly intuitive.
```typescript
function fetchSecureData(token: string): Promise {
return new Promise((resolve, reject) => {
if (token === "valid-token") {
resolve("Access Granted: Sensitive Data");
} else {
reject(new Error("Unauthorized Access"));
}
});
}
async function handleDataRequest(token: string) {
try {
const data = await fetchSecureData(token);
console.log(data);
} catch (error) {
// Catching both synchronous errors and rejected promises
if (error instanceof Error) {
console.error(`Error caught: ${error.message}`);
} else {
console.error("An unknown error occurred.");
}
} finally {
console.log("Request operation completed.");
}
}
// Test cases
handleDataRequest("valid-token");
handleDataRequest("invalid-token");
```
---
## Key Considerations and Best Practices
1. **Avoid the "Sequential Trap"**: Do not use `await` on independent asynchronous operations sequentially. If two operations do not depend on each other's results, trigger them concurrently and use `Promise.all()` to wait for them.
2. **Always Handle Rejections**: Unhandled promise rejections can crash your application or leave it in an unstable state. Always wrap your `await` calls in `try...catch` blocks or chain a `.catch()` block to the async function call.
3. **TypeScript Type Safety**: TypeScript is excellent at inferring the resolved type of an awaited Promise. However, explicitly defining the return type of your async functions as `Promise` improves code readability and API contract enforcement.
4. **Target Compilation**: Ensure your `tsconfig.json` target is set to `ES6` (ES2015) or higher to natively support Promises, or configure a polyfill if targeting older environments like ES5.
YouTip