gio
gio

Reputation: 891

Resolve all promises in an array of json - javascript

I need to resolve all promises in an array of json, like this:

let list = [
    { 
        id: 1,
        data: new Promise((resolve, reject) => {
            resolve('Cat')
        })
    },
    { 
        id: 2,
        data: new Promise((resolve, reject) => {
            resolve('Dog')
        })
    },
    { 
        id: 3,
        data: new Promise((resolve, reject) => {
            resolve('Mouse')
        })
    }
]

I use bluebird promises. I used a for cycle to iterate all items, I would know if there was some way more elegant.

Expected result:

[ { data: 'Cat', id: 1 },
  { data: 'Dog', id: 2 },
  { data: 'Mouse', id: 3 } ]

Upvotes: 1

Views: 8344

Answers (6)

TJBlackman
TJBlackman

Reputation: 2313

Resolve Promise.all() to an actual usable array of JSON.

The problem: Promise.all() resolves to an array of resolved promises. To see why this is an issue, copy and paste this into your console:

var promise1 = fetch('https://swapi.dev/api/people/2'); // C-3PO
var promise2 = fetch('https://swapi.dev/api/people/3'); // R2-D2

Promise.all([promise1, promise2])
    .then(res => console.log(res)); // resolved promises - trash...

See how there's no actual usable data in those resolved promises..? On the web, you need to call another promise to convert them to text or html or, most likely, beloved json. But how can you do this efficiently?

Well, then solution to our Promise.all() issue is... more Promise.all()!!!

Example:

var promise3 = fetch('https://swapi.dev/api/people/1'); // Luke
var promise4 = fetch('https://swapi.dev/api/people/4'); // Luke's daddy

Promise.all([promise3, promise4])
    .then(res => Promise.all([res[0].json(), res[1].json()]))
    .then(res => console.log(res)); // real data :)

Hope this helps someone! Thanks!

Upvotes: 2

Vikash Dahiya
Vikash Dahiya

Reputation: 5801

you can use lodash lib to minimize your code

const _ = require('lodash');

Promise.all(_.map(list, 'data')).then((data)=>{
    list.map((item,ind)=>{item.data = data[ind]});
    console.log(list);
})

Upvotes: 0

Jaromanda X
Jaromanda X

Reputation: 1

This should work, Promise.all and array.map like the others, but the result is correct

let list = [
    { 
        id: 1,
        data: new Promise((resolve, reject) => {
            resolve('Cat')
        })
    },
    { 
        id: 2,
        data: new Promise((resolve, reject) => {
            resolve('Dog')
        })
    },
    { 
        id: 3,
        data: new Promise((resolve, reject) => {
            resolve('Mouse')
        })
    }
]    

Promise.all(list.map(item => item.data.then(data => ({...item, data}))))
// that's it, that's what you want, the rest is for show now
.then(results => {
   console.log(results);
});

though, that's Native Promises ... you may want to look into Promise.props and/or Promise.map in bluebird for possibly simpler code yet

It could well be as simple as

Promise.map(list, Promise.props)
.then(results => {
    console.log(results);
});

tested the above, and yes, it is that simple - the snippet below has my own version of Promise.map and Promise.props - and works (at least in this case) identically to bluebird

Promise.props = obj => {
    const keys = Object.keys(obj);
    return Promise.all(Object.values(obj)).then(results => Object.assign({}, ...results.map((result, index) => ({[keys[index]]: result}))));
};

Promise.map = (array, fn, thisArg) => Promise.all(Array.from(array, (...args) => fn.apply(thisArg, args)));

let list = [
    { 
        id: 1,
        data: new Promise((resolve, reject) => {
            resolve('Cat')
        })
    },
    { 
        id: 2,
        data: new Promise((resolve, reject) => {
            resolve('Dog')
        })
    },
    { 
        id: 3,
        data: new Promise((resolve, reject) => {
            resolve('Mouse')
        })
    }
]    

Promise.map(list, Promise.props)
.then(results => {
    console.log(results);
});

Upvotes: 7

Ali Malek
Ali Malek

Reputation: 722

You just need create an array of promises. you can do it with for or map

let promises = []

for(var i=0; i < list.length; i++)
  promises.push(list.data)

Promise.all(promises).then(resultList => { ... }).catch(err => { ... })

or simplest may with map

Promise.all(list.map(p => p.data)).then(resultList => { ... }).catch(err => { ... })

Upvotes: 0

explorer
explorer

Reputation: 952

With Promise.all & some JavaScript.

let list = [];
let promise = Promise.all(list.map(entry => entry.data));
promise.then((results) => {
  let final = results.map((result, index) => {
    return {data: result, id: list[index].id};
  });
  console.log(final);
});

Upvotes: 1

sp00m
sp00m

Reputation: 48807

Promise.all may be a good fit here:

Promise.all(list.map(entry => entry.data)).then((resolved) => {
  // ...
});

Upvotes: 0

Related Questions