Q:

then() function of Promise.all executing before promises are finished - Ionic/Angular

I am setting up caching for the first time with ionic. Here is the code:
listProducts(): Promise < any > {
    let cacheKey = 'products';
    this.cache.removeItem(cacheKey);
    let promises_array:Array<any> = [];
    let results;
    return new Promise((resolve, reject) => {
        this.cache.getItem(cacheKey).catch(() => {
            this.list = this.af.list('/products');
            this.subscription5 = this.list.subscribe(items => {
                for (let x = 0; x < items.length; x++) {
                    promises_array.push(new Promise((resolve, reject) => {
                        console.log(JSON.stringify(items[x].customMetadata) + ":   this is the customdata (((()()()()()");
                        let storageRef = firebase.storage().ref().child('/settings/' + items[x].customMetadata.username + '/profilepicture.png');
                        storageRef.getDownloadURL().then(url => {
                            console.log(url + "in download url !!!!!!!!!!!!!!!!!!!!!!!!");
                            items[x].customMetadata.profilepic = url;
                        }).catch((e) => {
                            console.log("in caught url !!!!!!!$$$$$$$!!");
                            items[x].customMetadata.profilepic = 'assets/blankprof.png';
                        });
                        //this.startAtKey = item.$key;
                        this.productListArray.push(items[x].customMetadata);
                    }));
                };
            })
            results = Promise.all(promises_array);
            results.then(() => {
                //setTimeout(() => {
                console.log(JSON.stringify(this.productListArray) + " value value vlaue productlistarray");
                this.productListArray.reverse();
                return this.cache.saveItem(cacheKey, this.productListArray);
                //}, 3000);
            })
        }).then(data => {
            console.log("Saved data: ", data);
            resolve();
        })
    })
}

Basically the line console.log(JSON.stringify(this.productListArray) + " value value vlaue productlistarray"); prints an empty array - []. There should be data in this variable because the code shouldn't execute before all of the promises are done. You'll notice I have a setTimeout commented out - when I comment it in, it works - but this is obviously not an acceptable solution, I'm just showing that its a timing problem with the promises. Any help would be great.

A:

I think the problem lies in this line
this.list.subscribe(items => {

Basically, list is still fetching when  
console.log(JSON.stringify(this.productListArray) + " value...

is run. So I expect promises_array is empty (you can check that out).  
You can sort that out by mapping list (either map() or flatMap(), need to check which) into an array of promises instead of pushing individual promises in.
I think this is the map (or flatMap) code, but it needs testing. Note, lots of returns are required at every indent level.
const promises_array = this.list.map(items => {
  return items.map(item => {
    return new Promise((resolve, reject) => {
      console.log(JSON.stringify(items[x].customMetadata) + ":   this is the customdata (((()()()()()");
      let storageRef = firebase.storage().ref().child('/settings/' + items[x].customMetadata.username + '/profilepicture.png');
      return storageRef.getDownloadURL().then(url => {
        console.log(url + "in download url !!!!!!!!!!!!!!!!!!!!!!!!");
        items[x].customMetadata.profilepic = url;
      }).catch((e) => {
        console.log("in caught url !!!!!!!$$$$$$$!!");
        items[x].customMetadata.profilepic = 'assets/blankprof.png';
      });
      this.productListArray.push(items[x].customMetadata);
    }));    
  })
}
Promise.all(promises_array)
  .then(() => {
    console.log(JSON.stringify(this.productListArray) + " value value vlaue productlistarray");
    this.productListArray.reverse();
    this.cache.saveItem(cacheKey, this.productListArray);
})

