JavaScript is single-threaded. Async programming allows JS to handle long running tasks without blocking the main execution thread, ensuring a responsive user experience.
## Callbacks
Callbacks are functions passed as arguments to other functions and are executed after the completion of a task.
Callbacks were the original way to handle async operations in JavaScript but are now considered outdated, resulting in "callback hell."
```javascript
myDiv.addEventListener("click", function() {
// execute callback
});
```
## Promises
A promise represents a value that may be available now, in the future, or never.
Promises provide a cleaner and more robust way to handle async operations.
##### Promise states
- Pending: Initial state, neither fulfilled or rejected.
- Fulfilled: Operation completed successfully.
- Rejected: Operation failed.
```javascript
function fetchUser(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (isValid(userId)) {
const fetchedUser = ...;
resolve(fetchedUser);
} else {
reject(new Error('User not found.'));
}
}, 1000);
});
};
```
```javascript
fetchUser('123')
.then((user) => { /* handle result */ })
.catch((error) => { /* handle error */ })
.finally(res => { /* called regardless of success or failure */ });
```
##### Handling multiple promises
`Promise.all` allows you to wait for multiple promises to resolve, returning a single promise.
```javascript
Promise.all([promise1, promise2])
.then((result) => { /* [result 1, result 2] */ })
```
`Promise.race` returns a promise that resolves or ejects as soon as one of the promises in the array resolves or rejects.
```javascript
Promise.race([promise1, promise2])
.then((result) => { /* Result of first resolved promise */ })
```
## async/await
`async`/`await` are syntactic sugar over promises, making async code read more like synchronous code. (Really. The async function actually returns a promise. Returning from an async function resolves the promise. Throwing an error rejects the promise.)
`async` declares an asynchronous function that returns a promise.
`await` pauses the execution of an async function until the promise is resolved or rejected.
See the difference below, both code blocks do the exact same thing:
```javascript
// fetch using promise syntax (without async/await)
function getPersonsInfo(name) {
return server.getPeople().then(people => {
return people.find(person => { return person.name === name });
});
}
```
```javascript
// fetch using async/await syntax
async function getPersonsInfo(name) {
const people = await server.getPeople();
return people.find(person => { return person.name === name });
}
```
#### Error handling
Use try...catch blocks to handle errors in async/await.
```javascript
async function asyncFetch(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
return data;
} catch (err) {
// handle error
}
}
```
Since `async` functions return a promise, you can handle errors at their call site by appending `.catch()`, like any other promise.
```javascript
asyncFetch(url)
.then(data => { /* handle data */ })
.catch(err =>. { /* handle error */ });
```