2

I have an array of questions.
Each question has some answers which are some files to upload.
Everything goes well instead of the fact that the API call is not waiting for Promise.all to finish.

Here are the steps:

  1. map through questions array, if a question is image type, then get all the files and try to upload them.

  2. after upload resolve all the promises from upload and add an answer to that question the result of Promise.all();

  3. After the loop through all the questions is ready, make an API call to save into DB which now is not waiting to upload all the files and resolve everything in that array.

export function sendReview (taskId, companyId, questions, navigation) {
  return async (dispatch) => {
    
    dispatch(actions.sendReview.pending());
    try {
      let user = await getUser();
      user = JSON.parse(user);
      
      questions.map(async question => {
        if (question.type === 'image') {
          let images = question.answer;
          if (images.length > 0) {
            const results = images.map(async image => {
              return await imageApi.upload(image).then(res => {
                return res.url;
              });
            });
            question.answer = await Promise.all(results).then(completed => {
               return completed;
            });
          }
        }
      });
      
      const data = await tasksApi.sendReview({
        task_id: taskId,
        company_id: companyId,
        user_id: user.id,
        questions: JSON.stringify(questions)
      });

      if (data.status === 201) {
        markAsCompleted(taskId);
        navigation.navigate('MyTasks');
        dispatch(actions.sendReview.success({}));
      }
      else {
        dispatch(actions.sendReview.error());
      }
    } catch (err) {
      dispatch(actions.sendReview.error(err));
    }
  };
}

Here is the function used.

How can I make sure that all the items in .map() are ready and just after that make API call?

GottZ
  • 4,824
  • 1
  • 36
  • 46
andreirat
  • 23
  • 3
  • On the inner loop, you are doing `await Promise.all(results)`. On the outer loop, you're doing nothing! – Bergi Nov 25 '18 at 12:08
  • You [don't need `return await`](https://stackoverflow.com/a/43985067/1048572) – Bergi Nov 25 '18 at 12:09

2 Answers2

1

Use Promise.all to await promises in an array

Promise.all(questions.map(...))

jamesjaya
  • 665
  • 5
  • 15
1

To give you an example from code I made quite some time ago:

await Promise.all((await readdir(repoPath, "utf8")).map(async file => {
  if (!/\.mjs$/.test(file)) return;
  const filePath = `${repoPath}/${file}`;
  log(`importing "${file}"`);

  const module = await import(filePath);

  const meta = {
    repository,
    file,
    filePath,
    description: module.description || {}
  };

  module.default((...args) => createModule(meta, ...args));
}));

If you have asyncronous mapping handlers, you'll need to keep in mind, the content of the resulting map contains promises.

Promise.all() will help you with that.

In your case, all you need to do is change:

questions.map(async(question) => {
  if(question.type === 'image'){
    let images = question.answer;
    if(images.length > 0){
      const results = images.map(async (image) => {
        return await imageApi.upload(image).then(res => {
          return res.url;
        });
      });
      question.answer = await Promise.all(results).then((completed) => {
        return completed
      });
    }
  }
});

as follows:

await Promise.all(questions.map(async(question) => {
  if(question.type === 'image'){
    let images = question.answer;
    if(images.length > 0){
      const results = await Promise.all(images.map(async (image) => {
        return await imageApi.upload(image).then(res => {
          return res.url;
        });
      }));
      question.answer = results.then((completed) => {
        return completed
      });
    }
  }
}));
GottZ
  • 4,824
  • 1
  • 36
  • 46
  • I wasn't thinking about it, since my .map() didn't return an array of promises, but wrapping .map() in Promise.all() helped. – andreirat Nov 25 '18 at 11:08
  • ye. it's a pain to figure this out. took me quite a while and a bit of debugging. – GottZ Nov 25 '18 at 11:12