2

I would like to call several times my api and then return only my object in errors (here it's workers)

What do you think about this implementation? (I don't like the .then(()=> false but I didn't figure out better implementation even with reduce)

I would like to avoid to filter after the Promise.all

Thanks

updateWorkersStatusOnMissions: (workersOnMissions, apiService) => {
    const updateWorkerStatusOnMissionPromises = workersOnMissions
      .map(workerOnMission =>
        apiService.put('missions', formatWorkerOnMission(workerOnMission))
          .then(() => false)
          .catch(() => formatWorkerInError(workerOnMission))
      )
    return Promise
      .all(updateWorkerStatusOnMissionPromises)
      .then(filter(Boolean))
  },
Pierre Trollé
  • 426
  • 3
  • 10

2 Answers2

2

What I usually do is introduce some kind of "box" around the results which allow to tell the "kind" of result I get from a promise. A promise will always return a value to you, but depending upon where it was provided then(onSuccess, onFail) the type is different.

const into = type => val => ({ type, val })

const arrayOfstuff = [];

const arrayOfPromises = arrayOfstuff.map(stuff => makePromise(stuff)
  .then(into("success"), into("error")))

const successFullStruff = Promise.all(arrayOfPromises)
  .then(filter(result => result.type === "success"))

const failedStuff = Promise.all(arrayOfPromises)
  .then(filter(result => result.type === "error"))
adz5A
  • 2,012
  • 9
  • 10
  • Upon reading the comments, it seems it is quite close to the "reflect" solution linked in the comments. Not sure about why it is called like that as it is merely some form of "tagging" data. – adz5A Aug 28 '18 at 13:19
0

If you want to partition a list/array based on a predicate (in this case, whether the Promise is resolved or rejected), the use partition!

 const partitionP = coll => {
   const resolved = [];
   const rejected = [];
   return Promise.all(coll.map(p => {
     p.then(result => resolved.push(result)).catch(err => rejected.push(err));
   }).then(_ => [resolved, rejected]);
 });

 async getApiResults = workersOnMissions => {
   const [results, errors] = await partitionP(workersOnMissions.map(workerOnMission => {
     return apiService.put('missions', formatWorkerOnMission(workerOnMission));
   }));
   // do something with the results/errors or just return them
 };

You do need a Promise-aware partition here, because Promise.all will reject immediately if any of the Promises in the array reject, meaning you need to manually manage the iteration (in this case by making sure to .catch any rejections and put them back on the happy path). Otherwise you could do something simpler like mapping the api call to get an array of Promises and then partitioning the result in the .then handler.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83