2

I want to return the consolidated results from calling many async/await functions. Consider my (wrong) pseudocode below

const getRemoteData = async function(uri) {
    // get result from remote server via XMLHttpRequest
    return result;
}

const finalResult {};
const result1 = getRemoteData('http://…');
result1.forEach(async record => {
    // each record has a key for another URI
    const result2 = await getRemoteData(record["uri"]);

    // result2 has a key for yet another URI
    const result3 = await getRemoteData(result2["uri"]);
    finalResult[ result2["uri"] ] = result3;
})

console.log(finalResult);

Of course, since console.log(finalResult) is called before all the interim calls in the forEachloop have completed, finalResult is empty. How do I return finalResult after all the entries in result1 have been processed? I am using the latest version of nodejs and, if possible, would rather not use any other Promise library. From what I understand, the new async/await capabilities should enable me to accomplish what I want.

punkish
  • 13,598
  • 26
  • 66
  • 101

1 Answers1

6

You need to use .map instead of .forEach in order to .map each item in result1 to a Promise that resolves once the associated result3 has been assigned to finalResult. Then, use Promise.all on that array, which will resolve once all of its Promises have resolved, after which finalResult will be populated with everything you need:

const getRemoteData = function(uri) {
  // pretty sure you didn't mean to recursively call getRemoteData:
  return someApiCall(uri);
}
const result1 = await getRemoteData('http://…');
const finalResult = {};
await Promise.all(result1.map(async (record) => {
  const result2 = await getRemoteData(record.uri);
  const result3 = await getRemoteData(result2.uri);
  finalResult[result2.uri] = result3;
}));
console.log(finalResult);

(note that instead of an async function that await's something and returns it immediately, you may as well just return the Promise directly instead - also, dot notation is usually preferable to bracket notation, bracket notation is when you need to use a variable property name)

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • bravo! Thanks for guiding me to the right solution. One question: where is the documentation that would have helped me figure out on my own that I needed to use `map` and not `forEach`? – punkish Nov 28 '18 at 08:19
  • 1
    `forEach` runs *synchronously* (as do all Javascript functions in the same block without `await` on that line), so I would have googled something like `await foreach`, which could take you to [here](https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404) or [here](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – CertainPerformance Nov 28 '18 at 08:25