Js Async Await
Before explaining `async/await`, we need to first understand the asynchronous programming concept in JavaScript. You can refer to: (/category/js-async.html).
JavaScript is a single-threaded language, meaning it can only execute one task at a time. To avoid long-running tasks blocking the main thread, JavaScript uses an asynchronous programming model.
### Asynchronous vs Synchronous
* **Synchronous programming**: Code executes in order, and the next operation only executes after the previous one completes.
* **Asynchronous programming**: Some operations are put into the "task queue", the main thread continues executing subsequent code, and processes tasks in the queue when the main thread is idle.
#### Example
```javascript
// Synchronous Example
console.log('1');
console.log('2');
// Output: 1, 2
// Asynchronous Example
console.log('1');
setTimeout(() => console.log('2'), 0);
console.log('3');
// Output: 1, 3, 2
```
---
## Problems with Callback Functions
Before `async/await` appeared, JavaScript mainly used callback functions to handle asynchronous operations, but this led to "Callback Hell".
#### Example
```javascript
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
getMoreData(c, function(d) {
console.log(d);
});
});
});
});
```
This nested structure makes code difficult to read and maintain.
---
## Introduction of Promise
ES6 introduced the `Promise` object to solve the callback hell problem.
#### Example
```javascript
function getData() {
return new Promise((resolve, reject) => {
// Asynchronous operation
setTimeout(() => resolve('data'), 1000);
});
}
getData()
.then(data => {
console.log(data);
return getMoreData(data);
})
.then(moreData => {
console.log(moreData);
})
.catch(error => {
console.error(error);
});
```
Although `Promise` improved the callback problem, the `.then()` chain calls are still not intuitive enough.
---
## async/await Syntax
ES2017 introduced `async/await`, which is built on top of `Promise` and makes asynchronous code look and behave like synchronous code.
### async Function
Add the `async` keyword before the function declaration to indicate that the function is asynchronous:
```javascript
async function fetchData() {
// Function body
}
```
`async` functions always return a `Promise`:
* If the return value is not a `Promise`, it will be automatically wrapped in a resolved `Promise`.
* If an exception is thrown, it will return a rejected `Promise`.
### await Expression
`await` can only be used inside `async` functions:
```javascript
async function fetchData() {
const result = await somePromise;
console.log(result);
}
```
`await` pauses the execution of the `async` function and waits for the `Promise` to complete:
* If the `Promise` is resolved, it returns the resolved value.
* If the `Promise` is rejected, it throws an error (which can be caught with `try/catch`).
---
## Practical Application Examples
### 1. Basic Usage
```javascript
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function showMessage() {
console.log('Start');
await delay(1000);
console.log('After 1 second');
await delay(1000);
console.log('After another 1 second');
}
showMessage();
```
### 2. Error Handling
```javascript
async function fetchUserData() {
try {
const response = await fetch('https://api.example.com/user');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Failed to fetch data:', error);
}
}
```
### 3. Parallel Execution
If you need to execute multiple asynchronous operations in parallel, you can use `Promise.all`:
```javascript
async function fetchMultipleData() {
const [userData, productData] = await Promise.all([
fetch('/api/user'),
fetch('/api/products')
]);
const user = await userData.json();
const products = await productData.json();
return { user, products };
}
```
---
## Common Questions and Best Practices
### 1. Don't Forget await
```javascript
// Wrong example - forgetting await
async function example() {
const data = fetch('/api'); // Missing await
console.log(data); // Outputs Promise object
}
// Correct example
async function example() {
const data = await fetch('/api');
console.log(data); // Outputs actual data
}
```
### 2. Avoid Unnecessary async
```javascript
// Unnecessary - no await inside the function
async function unnecessaryAsync() {
return 42;
}
// Simpler implementation
function simpleFunction() {
return 42;
}
```
### 3. Top-level await
You can use `await` directly at the top level of a module (ES2022 feature):
```javascript
// In a module
const data = await fetch('/api');
console.log(data);
```
### 4. Performance Considerations
* **Sequential execution vs parallel execution**: Use `Promise.all` reasonably to improve performance.
* **Error handling**: Ensure all possible errors are caught.
---
## async/await vs Traditional Promise Comparison
| Feature | async/await | Promise then/catch |
| :--- | :--- | :--- |
| **Readability** | High, similar to synchronous code | Medium, chain calls |
| **Error handling** | Uses `try/catch` | Uses `.catch()` |
| **Debugging** | Easier, clear call stack | More difficult, call stack may not be clear |
| **Code structure** | Flatter | Nested or chained |
---
## Summary
`async/await` is a major improvement in JavaScript asynchronous programming. It:
1. Makes asynchronous code more readable and maintainable.
2. Is based on `Promise` and is fully compatible with existing `Promise` code.
3. Provides a more intuitive way of error handling.
4. Improves the debugging experience.
Although `async/await` doesn't completely replace `Promise`, in most cases it provides a more elegant solution. Understanding how `async/await` works and following best practices will greatly improve your JavaScript asynchronous programming skills.
YouTip