1

My code looks something like this:

(async () => {
  try {
    const results = await heavyCalculation();
    saveResultsToFiles(results);
  } catch (e) {
    handleError(e);
  } finally {
    process.exit(0);
  }
})();

const saveResultsToFiles = (results) => {
  results.forEach(result => {
    (async () => await saveResultFile(result));
  })
}

const saveResultFile = (result) => {
  return promiseToPreprocess(result)
    .then(processedResult => saveToFile(processedResult))
}

const promiseToPreprocess = async (result) => {
  // this function returns a promise to preprocess the data
}

const saveToFile = (data) => {
  // this function synchronously saves data to a file
}

I thought this code would

  1. perform calculations
  2. wait for each piece of the results to be preprocessed and saved to a file
  3. then exit

The first step works, as the program seems to await the heavy calculation results. However, it appears the finally clause is entered before the promise within the forEach-loop is resolved, causing the program to exit early. What am I doing wrong?

Toivo Säwén
  • 1,905
  • 2
  • 17
  • 33
  • 1
    `.forEach()` doesn't know anything about `async` functions. The functions return promises but `.forEach()` always ignores return values. – Pointy Apr 20 '20 at 13:35

2 Answers2

3

You have two problems here:

  1. Your forEach loop in saveResultsToFiles does not return anything so you have no way to make other parts of your code "wait" for each item's promise to resolve.

  2. saveResultFile returns a promise but this promise is not awaited in your try block.

The result of both of these issues is that the try block only "starts" the process of saving to files but doesn't wait for it to finish before yieling to the finally block.

Here are solutions you could try.

  1. You need to be able to await each of the saveResultFile calls and for that you need to access the array of promises instanciated in saveResultsToFiles. With .map you will actually get an array of results (as opposed to .forEach):
const saveResultsToFiles = (results) => {
  return results.map(result => saveResultFile(result));
}
  1. Now that saveResultsToFiles actually returns an array of promises, you should await all of them before proceeding. This is exactly what Promise.all is for:
try {
    const results = await heavyCalculation();
    await Promise.all(saveResultsToFiles(results));
}
Sheraff
  • 5,730
  • 3
  • 28
  • 53
  • 1
    Perfect, I didn't realise it was the forEach function that caused the issue. As a slight tweak to your solution, I used `return Promise.all(results.map(...` and then simply `await saveResultsToFiles` as it feels like it is more logical to return one promise than an array of promises. – Toivo Säwén Apr 20 '20 at 14:43
  • So it appears it din't work entirely. The finally block is still called before the `.then` function of `saveResultFile`, meaning the file is not actually saved. How can I force the promise to be awaited along with the then clause before moving on to the finally block? – Toivo Säwén Apr 20 '20 at 15:14
  • For the `.then` to be called I needed to change the function within `.map` to `async result => await saveResultFile(result)`, although I don't understand why. – Toivo Säwén Apr 20 '20 at 15:48
  • @ToivoSäwén Are you sure `saveToFile` returns a promise? – Sheraff Apr 20 '20 at 16:57
  • ah, that's it. It didn't. – Toivo Säwén Apr 21 '20 at 07:34
-1

You are not awaiting saveResultsToFiles(results);

Try:

(async () => {
  try {
    const results = await heavyCalculation();
    saveResultsToFiles(results);
  } catch (e) {
    handleError(e);
  } finally {
    process.exit(0);
  }
})();

const saveResultsToFiles = async (results) => {
  results.forEach(result => {
    await saveResultFile(result);
  })
}

const saveResultFile = (result) => {
  return promiseToPreprocess(result)
    .then(processedResult => saveToFile(processedResult))
}

const promiseToPreprocess = async (result) => {
  // this function returns a promise to preprocess the data
}

const saveToFile = (data) => {
  // this function synchronously saves data to a file
}
wederer
  • 550
  • 2
  • 5
  • 17