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));
});
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…