Week 12: Modern JavaScript and Your Path Forward
Explore key ES6+ features, modules, asynchronous programming basics, and where to go next.
Explore Chapter 12Introduction to Asynchronous JavaScript: Promises, async/await.
JavaScript is single-threaded, meaning it can only do one thing at a time. However, many operations (like fetching data from a server, reading files, or timers) take time and shouldn't block the main thread (which would freeze the user interface).
Asynchronous programming allows these long-running tasks to happen in the background, letting the main thread continue. When the task completes, a callback, Promise, or async/await handles the result.
Promises
A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Promises provide a cleaner way to handle async operations compared to nested callbacks ("callback hell").
A Promise can be in one of three states:
- Pending: Initial state, neither fulfilled nor rejected.
- Fulfilled: The operation completed successfully.
- Rejected: The operation failed.
You typically work with Promises using .then() (for success) and .catch() (for failure).
// Example using the Fetch API (which returns a Promise)
console.log("Fetching data...");
fetch('https://jsonplaceholder.typicode.com/todos/1') // Returns a Promise
.then(response => { // First .then() handles the response object
if (!response.ok) { // Check if request was successful
throw new Error('Network response was not ok: ' + response.statusText);
}
return response.json(); // .json() also returns a Promise for parsing the body
})
.then(data => { // Second .then() handles the parsed data
console.log("Data received:", data);
})
.catch(error => { // .catch() handles errors from fetch() or any .then()
console.error('Fetch error:', error);
});
console.log("... Fetch request initiated (code continues to run)");
async/await (ES2017+)
async and await are syntactic sugar built on top of Promises, making asynchronous code look and behave more like synchronous code, which is often easier to read and write.
- async function: Declares a function that operates asynchronously. Such functions implicitly return a Promise.
- await: Used *inside* an async function to pause execution until a Promise settles (is fulfilled or rejected). It then resumes execution and returns the resolved value of the Promise (or throws the rejection reason).
// Same fetch example using async/await
async function fetchData() {
console.log("Fetching data (async)...");
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); // Pauses here until fetch completes
if (!response.ok) {
throw new Error('Network response was not ok: ' + response.statusText);
}
const data = await response.json(); // Pauses here until .json() completes
console.log("Data received (async):", data);
} catch (error) {
console.error('Fetch error (async):', error);
} finally {
console.log("... Fetch attempt finished (async)");
}
}
fetchData(); // Call the async function
console.log("... Async fetch request initiated (code continues to run)");
async/await significantly improves the readability of asynchronous code, especially when dealing with multiple dependent asynchronous operations.