YouTip LogoYouTip

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.
← Ts Type AliasTs Arrow Function β†’