How does promise.all work?

前端 未结 4 1248
余生分开走
余生分开走 2020-12-06 17:29

I started diggin\' in promises and found interesting Promise.all.

It is stated in MDN that

The Promise.all(iterable) method returns a promise

4条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-06 18:23

    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;
        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));
    });
    

提交回复
热议问题