Javascript Promise
JavaScript promises are a powerful tool for writing asynchronous code. They provide a way to handle asynchronous results in a synchronous-like manner, making it easier to reason about and work with asynchronous code.
Promises are objects that represent the eventual result of an asynchronous operation. They have a then method, which allows you to specify a callback to be executed when the asynchronous operation completes, as well as a catch method, which allows you to specify a callback to be executed if the asynchronous operation fails.
Here's an example of how you might use a promise to load some data from a server:
function loadData() {
return new Promise((resolve, reject) => {
// make an HTTP request to load the data
const xhr = new XMLHttpRequest();
xhr.open('GET', '/data');
xhr.onload = () => {
if (xhr.status === 200) {
// if the HTTP request is successful, resolve the promise with the response data
resolve(xhr.response);
} else {
// if the HTTP request is not successful, reject the promise with an error message
reject(new Error(`Unable to load data: ${xhr.statusText}`));
}
};
xhr.onerror = () => {
// if there is a network error, reject the promise with an error message
reject(new Error('Network error'));
};
xhr.send();
});
}
// use the promise
loadData()
.then(data => {
// do something with the data
console.log(data);
})
.catch(error => {
// handle any errors
console.error(error.message);
});
Promises also have a finally method, which allows you to specify a callback to be executed whether the promise is resolved or rejected. This is useful for cleaning up resources or performing other tasks that should be done regardless of the outcome of the asynchronous operation.
Promises can also be composed using methods such as Promise.all and Promise.race. Promise.all allows you to wait for an array of promises to all be resolved, while Promise.race allows you to specify a callback to be executed as soon as one of the promises in an array is resolved or rejected.
Chaining promises
One of the most powerful features of promises is the ability to chain them together. This allows you to build up a sequence of asynchronous operations, with each operation being executed only after the previous one has completed.
Here's an example of chaining promises:
loadData()
.then(data => {
// do something with the data
return transformData(data);
})
.then(transformedData => {
// do something with the transformed data
return storeData(transformedData);
})
.then(() => {
console.log('All operations completed successfully');
})
.catch(error => {
// handle any errors
console.error(error.message);
});
In this example, the transformData and storeData functions both return promises, and the then method is used to specify a callback to be executed when each promise is resolved. If any of the promises are rejected, the error will be caught by the catch method at the end of the chain.
Handling multiple asynchronous operations concurrently
In some cases, you may want to perform multiple asynchronous operations concurrently, rather than waiting for each one to complete in sequence. You can use the Promise.all method to do this.
Here's an example of using Promise.all:
Promise.all([loadData(), loadMoreData()])
.then(([data, moreData]) => {
// do something with the data and moreData
})
.catch(error => {
// handle any errors
console.error(error.message);
});
In this example, the loadData and loadMoreData functions both return promises, and Promise.all is used to wait for both of them to be resolved. If either of the promises are rejected, the error will be caught by the catch method.
Using async/await
JavaScript also has a new way of writing asynchronous code called async/await. This syntax allows you to write asynchronous code in a synchronous-like style, using the async keyword to define an asynchronous function and the await keyword to wait for a promise to be resolved.
Here's an example of using async/await with promises:
async function loadAndTransformData() {
try {
const data = await loadData();
const transformedData = await transformData(data);
return transformedData;
} catch (error) {
// handle any errors
console.error(error.message);
}
}
loadAndTransformData().then(transformedData => {
// do something with the transformed data
});
In this example, the loadAndTransformData function is marked as async, which means it returns a promise. The await keyword is used to wait for the loadData and transformData promises to be resolved. If either of these promises is rejected, the error will be caught by the catch block.