Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS async/await - why does await need async?

Why does using await need its outer function to be declared async?

For example, why does this mongoose statement need the function it's in to return a promise?

async function middleware(hostname, done) {
  try {
    let team = await Teams.findOne({ hostnames: hostname.toLowerCase() }).exec();
    done(null, team);
  } catch (err) { done(err); }
}

I see the runtime/transpiler resolving the Teams promise to it's value and async signaling it "throws" rejected promises.

But try/catch "catches" those rejected promises, so why are async and await so tightly coupled?

like image 715
Michael Cole Avatar asked May 25 '17 15:05

Michael Cole


3 Answers

I'm not privy to the JavaScript language design discussions, but I assume it's for the same reasons that the C# language requires async (also see my blog).

Namely:

  1. Backwards compatibility. If await was suddenly a new keyword everywhere, then any existing code using await as a variable name would break. Since await is a contextual keyword (activated by async), only code that intends to use await as a keyword will have await be a keyword.
  2. Easier to parse. async makes asynchronous code easier to parse for transpilers, browsers, tools, and humans.
like image 123
Stephen Cleary Avatar answered Oct 09 '22 07:10

Stephen Cleary


Copied from https://stackoverflow.com/a/41744179/1483977 by @phaux:

These answers all give valid arguments for why the async keyword is a good thing, but none of them actually mentions the real reason why it had to be added to the spec.

The reason is that this was a valid JS pre-ES7

function await(x) {
  return 'awaiting ' + x
}

function foo() {
  return(await(42))
}

According to your logic, would foo() return Promise{42} or "awaiting 42"? (returning a Promise would break backward compatibility)

So the answer is: await is a regular identifier and it's only treated as a keyword inside async functions, so they have to be marked in some way.

Fun fact: the original spec proposed more lightweight function^ foo() {} for async syntax.

like image 38
Michael Cole Avatar answered Oct 09 '22 06:10

Michael Cole


Because using await inside middleware function means the middleware function can't return a result immediately (it must wait until await is settled) and middleware function callers must wait until the promise (returned from middleware function) is settled.

like image 26
Mihail H. Avatar answered Oct 09 '22 06:10

Mihail H.