leebyron/async-to-gen

SyntaxError: Unexpected identifier yield

ilkkao opened this issue · 10 comments

This snippet works on Chrome 54 with native async/await

async function test() {
    return !!await console.log('works');
}

test();

With async-to-gen it leads to parse error. Simple workaround is to write return !!(await ....) instead.

Interesting. Are the parse rules different for await expressions and yield expressions? That would be annoying!

Yes, await has better precedence than yield. Related standards discussion I found: https://esdiscuss.org/topic/precedence-of-yield-operator

await abc -> (yield abc) everywhere should work?

Thanks for the links. Indeed they are.

Await: https://tc39.github.io/ecmascript-asyncawait/#prod-AwaitExpression
Yield: https://tc39.github.io/ecma262/2016/#prod-YieldExpression

Not only are the precedence rules different, but a yield can appear on its own line and is a candidate for ASI.

looks like this ends up creating a nasty error here:

let obj = await existing
      ? Update({ id: existing.id, article }, ctx)
      : Create({ article }, ctx)

transforms to:

let obj = (yield existing)
      ? Update({ id: existing.id, article }, ctx)
      : Create({ article }, ctx)

Ends up creating and updating in parallel w/o waiting :-O

I believe that's actually the correct interpretation of the async code above. Await and yield have different precedence rules, where await applies before many other forms apply, including the ternary.

So what you're illustrating here isn't a bug, just code thats working correctly but is ambiguous to the reader and leading to surprise.

If you instead write: await (x?y:z) then you'll remove that ambiguity.

Imagine the opposite interpretation for a different scenario, like registering a username during login:

let msg = await isAvailable(username) ? "It's all yours!" : "Sorry, not available"

You can see how the tighter binding of await to only the condition in the ternary would be the right thing, otherwise the bug would be to think all usernames were available if isAvailable() returns a promise.

ahhh... that makes sense. thanks for clarifying. it does seem a bit silly that the spec diverges on the precedence of yield and await to such an extent. seems like this will lead to a lot of unexpected errors, unless they're going to change yields precedence too.

The ship has sailed on yield, and as far as I understand there are good reasons for them to diverge and that was part of the discussion around designing async functions. Yield is more similar to return, while await is more like a unary operator (like typeof)