Promise
An object that will eventually be returned by an asynchronous function, which represents the current state of the operation
- All asynchronous functions return a promise.
- (amazing) MDN docs
- States include
- Pending - The initial state
- Waiting to get the data back from the API: operation not yet succeeded or failed
- Fulfilled - Successfully resolved (
.then()is called) - Rejected - Operation failed (
.catch()is called)
- Pending - The initial state
- Other states
- Completed - Promise is no longer pending (either fulfilled or rejected)
- Resolved - Promised is completed, or it’s “locked in” to follow the state of another promise (advanced concept)
- A
Promiseconstructor receives a single argument: an executor function- This executor function receives two callbacks:
resolve(value)andreject(reason) - Inside the executor, you must call either
resolveorrejectto settle the promise
- This executor function receives two callbacks:
- With a promise-based API, the asynchronous function starts the operation and returns a
Promiseobject- You can then attach handlers to this
Promiseobject, and these handlers will be executed with the operation has succeeded or not
- You can then attach handlers to this
Creating your own - resolve(), reject()
- functions you need to use when creating your own promise
- automatically provided to you by JavaScript when you create a new
Promise resolve()- This function is called when the asynchronous operation inside the Promise succeeds, and it fulfills the Promise.
- The result passed to
resolveis what the Promise will resolve to (i.e., the value you get when the Promise is successful).
reject()- This function is called when the asynchronous operation inside the Promise fails, and it rejects the Promise.
- The argument passed to
rejectis usually an error or a message explaining why the operation failed.
- The names don’t really matter (
resolveorreject) but the ORDERING matters- You can have
new Promise((apple, banana))
- You can have
fetch()
fetch()function is a modern API used to make network requests, and it always returns a Promise- A function where you give a URL of an API, then it “fetches” the stuff from the URL
- The first Promise
- Resolves to a
Responseobject - Only contains metadata about the response (like status code
200OK or404Not Found), but NOT the actual data you want
- Resolves to a
- The second Promise
- To get the data (e.g. in JSON format), you MUST call another method on the
Responseobject, such as.json(), which also returns a Promise - This second Promise resolves to the actual data (the parsed JSON)
- To get the data (e.g. in JSON format), you MUST call another method on the
Handlers: then(), catch(), finally()
- They are handlers attached to a promise, and they accept callback functions that runs on success/failure
then()- Receives a function to be executed when promise is fulfilled
- allows you to do other things asynchronously while promise is not yet fulfilled!
- each
.then()returns a promise
catch()- Receives a function to be executed when promise is rejected
- called when any of the asynchronous function calls fail
finally()- Runs at the last regardless of success or failure, does not receive the success/failure value
Example of using fetch withthen and catch handlers:
const fetchPromise = fetch('https://api.example.com/data')
// This .then() handles the first Promise (the Response object)
.then(response => {
// Check if the HTTP request was successful
if (!response.ok) {
// If not, throw an error to trigger the .catch()
throw new Error('Network response was not ok');
}
// Call .json() to parse the data. This returns a new Promise.
return response.json();
})
// This .then() handles the second Promise (the actual data)
.then(data => {
console.log('Here is the data:', data);
})
// This .catch() handles any errors from the fetch or the .then() blocks
.catch(error => {
console.error('Fetch failed:', error);
})
.finally(() =>
console.log("Done fetching") // final callback
); - We just did promise chaining
- Instead of calling the second
then()inside the handler for the firstthen(), we return the promise returned byjson()and call the secondthen()on that return value - we avoid callback hell
- Instead of calling the second
- Note on
response.okand.catch()response.ok- Check for HTTP errors (like 404 or 500) after the server has successfully sent a response
- Network connection is still successful → just sees if HTTP requests worked lol
catch()- Handle network failures or anything that prevents the request from completing
- Gets ANY response back if it just cannot connect to the server (user is offline, server doesn’t exist, fundamental network error, etc)
Multiple promises (promise chain)
- Main functions include
.all()and.any(), there are more (Promise web docs)
Promise.all()
- Takes an array of promises and returns a single promise
- Sometimes you need promises to be fulfilled but they don’t depend on each other
- The promise returned by
Promise.all()- fulfilled when and if all the promises in the array are fulfilled
- the
then()handler is called with an array of all the responses, in the same order that the promises were passed intoall()
- the
- rejected when and if any of the promises in the array are rejected (
catch()handler is called)
- fulfilled when and if all the promises in the array are fulfilled
const fetchPromise1 = fetch(
"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json",
);
const fetchPromise2 = fetch(
"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found",
);
const fetchPromise3 = fetch(
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json",
);
Promise.all([fetchPromise1, fetchPromise2, fetchPromise3])
.then((responses) => {
for (const response of responses) {
console.log(`${response.url}: ${response.status}`);
}
})
.catch((error) => {
console.error(`Failed to fetch: ${error}`);
});Promise.any()
- You might need any one of a set of promises to be fulfilled and don’t care which one
- Like
Promise.all()except that it’s fulfilled as soon as any of the array of promises is fulfilled, or rejected if all of them are rejected
const fetchPromise1 = fetch(
"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json",
);
const fetchPromise2 = fetch(
"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found",
);
const fetchPromise3 = fetch(
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json",
);
Promise.any([fetchPromise1, fetchPromise2, fetchPromise3])
.then((response) => {
console.log(`${response.url}: ${response.status}`);
})
.catch((error) => {
console.error(`Failed to fetch: ${error}`);
});async/await
- A newer syntax that makes working with Promises much cleaner and easier to read
- Lets you write asynchronous code that looks synchronous
async- Place this keyword before a function declaration:
async function myDataFunction() {...} - An
asyncfunction automatically returns a promise - Only inside an
asyncfunction, you can use theawaitkeyword before a call to a function that returns a promise
- Place this keyword before a function declaration:
await- Place the
awaitkeyword in front of any expression that returns a Promise (likefetch()orresponse.json()) - It pauses the execution of the
asyncfunction at that line until the Promises settles (fulfilled or rejected)- If promise fulfilled →
awaitreturns the fulfilled value - If promise rejected →
awaitthrows an error
- If promise fulfilled →
- Because
awaitthrows an error if Promise is rejected, you MUST use atry... catchblock to handle errors
- Place the
// You must declare the function as async
async function getData() {
try {
// Pause execution until fetch() completes and gives the Response
const response = await fetch('https://api.example.com/data');
// Check if the HTTP response was ok
if (!response.ok) {
throw new Error('Network response was not ok');
}
// Pause execution until .json() completes and gives the data
const data = await response.json();
// This line only runs after the 'await' above is complete
console.log('Here is the data:', data);
} catch (error) {
// Any error (network failure, failed .json() parse) is caught here
console.error('Fetch failed:', error);
}
}
// Call the async function to start it
getData();- note that for
respose.json(),json()also returns a promise so you must useawait