-1

I had a different question closed, without my concept question being answered, so I'll try to ask it differently.

const retVal = foo()
console.log(retVal)

const retVal = await foo()
console.log(retVal)

In the first case, I would expect a potential case where retVal is undefined when the console.log call is made due to the sync nature of the flow.

In the second case, I would expect that retVal is guaranteed to have an answer by the time it hits the console.log, due to the await. This apparently doesn't seem to be the case as these can still be called as sync code, despite the await flag.

This led me to a 3rd code attempt:

const retVal = await foo()
retVal.then(console.log(retVal))

This seemed to me to be the way to guarantee that console.log would not execute until after foo() was completed, retVal had received the return value, and then could enter the .then callback.

What I observe in my program flow is that it seems to enter the .then() before the foo() completes. I see this in my console window, both with out of order console messages, and also the time I know foo() will take the printing inside the .then() happens much too quickly.

What am I missing about trying to block for control flow? I need guaranteed sequencing and some functions I need to call take time to return results.

thanks in advance!

Edit: Thanks for the answer, and in learning the coding system about promises, this makes a lot more sense now on how sync and async functions, promises, and code flows work. I see a lot of similar questions, so I'm glad that I'm not the only one who has to tackle this hurdle. :)

G-Force
  • 345
  • 3
  • 10
  • 3
    Your question lacks detail, what is `foo`, and yes it matters.. Your best knocking up a snippet to show an example.. – Keith Feb 12 '21 at 15:59
  • @Keith, you're right. At the time, I didn't even know why this comment mattered...and now I do, a few months later and some ramping on why promise/non-promise functions (a la foo) would matter. :) – G-Force Sep 18 '21 at 15:06

2 Answers2

1

First of all, this all depends upon whether the function you're awaiting returns a promise that resolves with your final value. There is no magic with await. All it does is wait for a promise to resolve and then get the resolved value from it. If you aren't awaiting a promise that resolves with your final value, it won't do anything useful for you.

So, if your function is returning the promise described above, then the difference between these two:

const retVal = foo()
console.log(retVal)

const retVal = await foo()
console.log(retVal)

Is that in the first, retVal will be your promise and in the second retVal will be the resolved value of the promise.


Then, in this example:

const retVal = await foo()
retVal.then(console.log(retVal))

There are multiple things wrong. First off, retVal will be a value, not a promise so you can't even use .then() on it. Then, if you changed it to this:

const promise = foo()
promise.then(console.log(retVal))

It still wouldn't work properly because you have to pass .then() a function reference like this:

const promise = foo()
promise.then((retVal) => console.log(retVal))
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • ok, so I know that I have a promise being returned from foo(). The flow seems to still cause something inside the promise.then() to execute, seemingly before foo() completes. is this possible? – G-Force Feb 12 '21 at 16:13
  • @G-Force - Please show your REAL code including the code inside of `foo()` if you want further help. There's only so far we go in theoretical explanations. I would guess that (as I describe above), either your promise isn't properly connected to your asynchronous operation or you aren't coding the `.then()` handler properly. – jfriend00 Feb 12 '21 at 16:27
1

TL;DR await only does something useful with promises.¹ So if you use it with a non-promise (like a function using XMLHttpRequst or setTimeout), await doesn't do anything useful.

In the first case, I would expect a potential case where retVal is undefined when the console.log call is made due to the sync nature of the flow.

Only if foo returns undefined. retVal will always be set to the return value from foo, synchronously. It won't be left unchanged and then assigned to later. (See below for what I think you were really asking.)

In the second case, I would expect that retVal is guaranteed to have an answer by the time it hits the console.log, due to the await.

See above, retVal will always receive the value from foo even without await.

This led me to a 3rd code attempt:

const retVal = await foo()
retVal.then(console.log(retVal))

That's incorrect. You can be certain that retVal will not contain a promise (or other thenable) when you use await, because by definition await waits for promises to settle.

I suspect your real code was more like this:

let retVal;
foo(data => {
    retVal = data;
});
console.log(retVal);

In that situation retVal won't be assigned to until or unless foo calls the callback you've given it, If foo does something asynchronous and doesn't call the callback until the asynchronous process is complete, retVal will not have been written to as of the console.log. And it doesn't matter whether you use await or not, assuming foo doesn't return a promise. (And if it does, it's unusual for it to also accept a callback, though there are some hybrid APIs out there.)

If foo is something that uses a callback style, and you want to use await with it, you have to wrap it in a promise as described in the answers to this question. There's no reason to do that with XMLHttpRequest because we have fetch, but it's useful for other API functions.

Then, when you have something that returns a promise, using await makes sense:

let retVal = await somethingThatReturnsAPromise();

Here's some questions with lots of useful answers in relation to this stuff:


¹ Or more generally, thenables.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875