1

I'm fairly new to Javascript and am looking for a little bit of clarification surrounding async/await when it comes to how/the order which Promises are resolved.

Say I have an async function, let's call it foo, that retrieves something and then writes it to a file using the fs.promises library.

const foo = async () => {
const x = await getX();
fs.promises.writeFile(path, x); //do I need to await this?};

I also have another async function that will call foo, and then do something with the file contents after they are written -- display it on a webpage, make a calculation, whatever.

const doSomething = async () => {
await foo(); //want to make sure foo resolves before calling otherFileFunc
otherFileFunc(); };

I want to ensure that the file contents have written, i.e. the promise of writeFile is resolved, before otherFileFunc executes. Is awaiting foo enough here, or can the promise of foo resolve before the promise of writeFile resolves? Should I await writeFile within foo to ensure this behavior, OR is the entire promise resolution of foo dependent on the promise of writeFile resolving and therefore awaiting it is superfluous?

Thank you!

Brandon
  • 21
  • 3

3 Answers3

1

Should I await writeFile within foo to ensure this behavior?

Yes.

Or is the entire promise resolution of foo dependent on the promise of writeFile resolving

No. The promise resolution of the async function is dependent only on the return from (or end of) its body. To make it depend on another promise, you must await that to suspend the execution of the async function. This is most easily achieved by considering to return the result of the called function (even if the value is undefined, the implicit result in your case is that the file is completely written) - you can only do that if you wait for the result.

async function foo() {
  const x = await getX();
  await fs.promises.writeFile(path, x);
}
async function foo() {
  const x = await getX();
  return fs.promises.writeFile(path, x);
}

There is no "implicit awaiting" of any promises created during the execution of an async function. If there was, you a) couldn't do something like Promise.all b) couldn't fire and forget a task if you actually don't want to wait.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Makes a lot of sense. Thank you for the explanation, I really appreciate it. Additionally, I now don't actually have to await foo now in doSomething, correct? Because I'm already awaiting the file write in foo, so awaiting doSomething seems useless since I'm not doing any thing with the result of foo. – Brandon Jan 22 '21 at 22:54
  • 1
    @Brandon You definitely need to. `foo()` is just a function call that returns a promise, there is no magic that makes `doSomething` automatically wait for it - you need to explicitly `await` it or `otherFileFunc()` will be called too early. You *are* doing something with the result: checking that the file was written completely without errors (that the promise did not reject). Even if there is no concrete value. – Bergi Jan 22 '21 at 23:00
  • Makes perfect sense when you explain it like that. Thank you very much. – Brandon Jan 22 '21 at 23:24
0

You had a file written in background while the foo function without an await statement resolved its promise before the file finished writing, which was incorrect.

Is awaiting foo enough here, or can the promise of foo resolve before the promise of writeFile resolves? Should I await writeFile within foo to ensure this behavior, OR is the entire promise resolution of foo dependent on the promise of writeFile resolving and therefore awaiting it is superfluous?

The promise of foo is controlled by the code of foo. Each await makes the promise wait for another promise. Function's promise will resolve when the end of function code is reached.

It's typical to await for each async function call to get the resulting value or to know when the task is finished (like in synchronous programming).

const foo = async () => {
  const x = await getX();
  await fs.promises.writeFile(path, x);
};

doSomething will work as expected as it'll wait for promise returned by foo() which in turn will wait for promise returned by getX() and will then wait for the promise returned by fs.promises.writeFile().

P.S.

MDN has a good article about async/await, it covers the concept, correlation with promises and error handling.

Vitalii
  • 2,071
  • 1
  • 4
  • 5
0
const foo = async () => {
const x = await getX(); 
fs.promises.writeFile(path, x); // do I need to await this?
}

writeFile is an asynchronous function returning a promise.

const doSomething = async () => {
await foo(); //
otherFileFunc(); };

otherFileFunc() will be called without writeFile being finished.

Solution:

const foo = async () => {
const x = await getX();
return fs.promises.writeFile(path, x); // do I need to await this?
}

Now, the writeFile, which itself returns a promise, is returned by foo(). Because foo() now returns the promise from writeFile, await foo() works as intended.

So, IMO your second answer is right.

the entire promise resolution of foo dependent on the promise of writeFile resolving and therefore awaiting it is superfluous?