2

I'm doing a little thought experiment about async/await with non-thenable values. Here, I have some code. I'm having trouble understanding why the output is 1 and then 2. Is it because when I invoke my asynchronous function increment(), the functionality inside gets wrapped in a Promise? I think I might get a better understanding if I could write this as without async/await and with Promises instead, but I'm not sure where to start.

let num = 0;

async function increment() {
    num += await 2;
    console.log(num);
}
increment();
num+=1;
console.log(num);

//1
//2

According to MDN, async functions return a Promise that is resolved to the value returned by the async function. Expressions in front of await that are not thenables are wrapped inside of a Promise.resolve and subsequent code gets wrapped in a then(). By looking at my exercise, I see that my async function does not feature a hard coded return but it does have an await. Since the await is followed by a non-thenable, I believe it should wrap that expression in a Promise.resolve, so it would be Promise.resolve(2). I thought my code block below would work at first but clearly the fulfilled value of the promise does not get added the way I want it to.

let num = 0;

function increment() {
    num += Promise.resolve(2).then((value) => value).then((value) => console.log(value));
}
increment();
num+=1;
console.log(num);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
lewislin
  • 21
  • 2
  • 1
    Related: [Async function with +=](https://stackoverflow.com/q/59802441) - see [Bergi's answer](https://stackoverflow.com/a/59802672) in particular. – VLAZ Feb 20 '23 at 22:06

1 Answers1

4

Your explanation is mostly right. The only problem is the

num +=

part outside of the asynchronous .thens. .then returns a Promise, not a value, so no matter what's on the right side of this:

num += Promise.resolve(2).then( ... ...

the result will be using the + operator on a Promise, which doesn't make sense.

What the first snippet does

num += await 2;
console.log(num);

is it waits a Promise that resolves to 2 to fulfill, and then it increments num with that value. Similarly, when using Promise.resolve, you need to put the increment action inside of the .then.

Another complication is += with await. When the line is first encountered, the value on the left (the existing variable) is essentially cached as the async action takes place. Then that cached value is retrieved when the async action completes, and added with the result. So, to replicate that, you'll need to store the current value of num in another variable first (otherwise you'd see it as 1, instead of 0, due to the num += 1 below).

(also, .then(value => value) is completely superfluous and may be removed)

let num = 0;

function increment() {
    const currNum = num;
    Promise.resolve(2).then((value) => {
        num = currNum + value;
        console.log(num);
    });
}
increment();
num+=1;
console.log(num);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Wow thank you for the explanation. And your snippet with the Promises version makes a lot of sense with mimicking the behavior of async/await. Thank you! – lewislin Feb 21 '23 at 02:13
  • https://stackoverflow.com/a/50870304/18327650 Here's an article about the assignment operator that goes into detail what it does under the hood! – lewislin Feb 21 '23 at 02:28