I started diggin' in promises and found interesting Promise.all.
It is stated in MDN that
The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved.
Which basically means that set promises resolve after and if all promises in argument list have been resolved. I tried to implement it. I made simply promise ajax call.
var get = function(url) {
return new Promise(function(resolve,reject) {
var xhtml=new XMLHttpRequest();
xhtml.open("GET",url);
xhtml.responseType = 'blob';
xhtml.onload = function() {
if(xhtml.status==200){
resolve(xhtml.response);
} else {
reject(Error("Error"+statusText));
}
}
xhtml.send();
});
}
get("one.jpg").then(function(response){
var blob = window.URL.createObjectURL(response);
var img = document.createElement("img");
console.log("Success"+response);
img.src = blob;
document.body.appendChild(img);
});
Which works fine. But after I tried to add Promise.all it threw an error.
Promise.all(get).then(function(response){alert("done")});
this as i said threw an error " Argument 1 of Promise.all can't be converted to a sequence." So I assume i didn't get the meaning of promise.all. How does it work?
all() method is the order of the maintained promises. The first promise in the array will get resolved to the first element of the output array, the second promise will be a second element in the output array and so on. Example 3: Here the Promise. all() method waits till all the promises resolve.
Promise. all([...]) is a useful helper function that lets you execute asynchronous operations in parallel, using a fail-fast strategy, and aggregate the results into an array.
As you can see, Promise. all executes code concurrently, but what is parallel execution? JavaScript is single-threaded and can only perform a single chunk of work at a time, so parallel execution is not possible with JavaScript, except for some circumstances such as web workers.
In this approach, we will use Promise. allSettled() which will be executed in a quite similar manner as Promise. all() method executed by taking promises as input in the single array and executing them sequentially.
Promise.all
takes an array (or any iterable) of promises and fulfills when all of them fulfill or rejects when one of them rejects. I think it's easier to understand if we implement it and understand why we need it.
A common use case might be to wait for the window to load and for the server to return data in order to run some code:
// a function that returns a promise for when the document is ready.
function windowReady(){
return new Promise(function(resolve){
window.addEventListener('DOMContentLoaded', resolve);
});
}
// function that returns a promise for some data
function getData(){
return fetch("/").then(function(r){ return r.json() });
}
Now, we want both of them to execute at the same time and then get the result. There are two items here but there could have easily been 5 things to wait for, or 100. So we use Promise.all
:
Promise.all([windowReady(), getData()]).then(function(results){
// results[1] is the data, it's all in an array.
});
Let's see how we can implement it:
function all(iterable){ // take an iterable
// `all` returns a promise.
return new Promise(function(resolve, reject){
let counter = 0; // start with 0 things to wait for
let results = [], i = 0;
for(let p of iterable){
let current = i;
counter++; // increase the counter
Promise.resolve(p).then(function(res){ // treat p as a promise, when it is ready:
results[i] = res; // keep the current result
if(counter === 0) resolve(results) // we're done
}, reject); // we reject on ANY error
i++; // progress counter for results array
}
});
}
Or, in even more ES6ness:
let all = iterable => new Promise((resolve, reject) => {
let arr = [...iterable], c = arr.length, results = [];
arr.map(Promise.resolve, Promise).
map((p, i) => p.then(v => {
r[i] = v;
if(--c === 0) resolve(r);
} , reject));
});
TLDR:
Promise.all
is a Javascript method that takes an iterable (e.g. Array
) of promises as an argument and returns a single promise when all the promises in the iterable argument have been resolved (or when iterable argument contains no promises). It resolves with an array of the resolved values and rejects with a single value of the first rejected Promise.
var promise1 = Promise.resolve(5);
var promise2 = Math.random() > 0.5? 1 : Promise.reject(1); // either resolves or rejects
var promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('foo'), 1000);
});
Promise.all([promise1, promise2, promise3]).then((val) => {
console.log(val);
}).catch((val) => {
console.log(val);
});
In the above example 3 Promises are passed into the Promise.all
function as an array. Promise 1 and 3 always resolve. Promise 2 either resolves or rejects based on the random Nr generator. This Promise.all method then returns a resolved or rejected Promise based on the random Nr generator.
Then the then()
method and the catch()
method can be called on this promise which is returned from Promise.all
. The then()
method gets an array of all the resolved values, [5, 1, 'foo']
in this case. The catch()
method gets the value of the first rejected Promise, 1
in this example.
This method is very usefull when you want to execute multiple async operations and need to something with the results after the async operations. When using Promise.all
all promises can be processed at the same time while still getting to operate on all the incoming data.
For example, when we need to get information using multiple AJAX requests and combine the data to something useful. It is essential to wait for all the data to be available otherwise we would try to combine non existing data which would lead to problems.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With