T.J. Crowder (2017-02-24T07:01:33.000Z)
tj.crowder at farsightsoftware.com (2017-02-24T07:27:49.898Z)
On Fri, Feb 24, 2017 at 5:18 AM, Šime Vidas <sime.vidas at gmail.com> wrote: > To clarify, the idea is to declare and kick off all the concurrent tasks > upfront (using local variables and the ‘lazy await’ keyword), and then just > continue writing the rest of the code ‘as if all the promises are > resolved’. The async function automagically pauses whenever needed, so it’s > no longer necessary to insert await operators throughout the code. > Not to be a naysayer, but I'm not a big fan of hidden behavior. If I see `sauce.determineCheese()`, the idea that the `.` is triggering a behind-the-scenes `await` isn't attractive. (Granted, there are already plenty of things it could be doing behind the scenes, with getters and proxies; but at least they're not changing the temporal semantics of the statement.) Domenic's version using current `async`/`await` syntax is nice and clear (one might tweak the variable names a bit to differentiate promises from resolved values, but...). Separately, I think you're going to run into implementational complexity. These automatic-`await` values are neither promises nor resolved values, they're a new beast with hidden `await` behavior; call them "hidden promises." Within an `async` function, most but not all [GetValue][1] operations on the variables/properties containing these hidden promises would need an "if this is a hidden promise, `await` it" guard: Any math operation, any string operation, any object operation, any time an `async` function passes the value into a non-`async` function, etc. Just about the only exception would be assignment (well, most assignments; more below), which would just copy the hidden promise. This becomes particularly problematic when you think about what it means to have one of these within a structure, like an array or object; what if we then pass its container to a non-`async` function? Do we recursively search the container for automatic-`await` values and `await` them before calling the non-`async` function? In what order? Similarly, the return values of `async` functions would need vetting, but (arguably) only if being returned to non-`async` functions, which makes for some new layer between caller and callee or an uncomfortable awareness in the `async` function of where its return value is going. Handling all of that sounds like a lot of runtime cost to simply hide `await` from ourselves. And updating all of this in existing engines seems like a lot of work. Then there's the question of which assignment operations would need to trigger a hidden `await`. Presumably not `let x = y;` where `y` is a hidden promise, that would largely defeat the purpose. But consider: ```js let x; function example() { a().then(() => { /* Do something */ }); } async function a() { async const hiddenPromise = getPromise(); // Or whatever the syntax would be... x = hiddenPromise; return await hiddenPromise; } example(); console.log(x); // What does this see? ``` Finally, there's the educational cost of explaining what triggers a hidden `await` to new JavaScripters. I can imagine a new inherently-async language with this sort of thing at its core (probably without non-`async` functions at all, avoiding a lot of the complexity above; instead making async-until-the-last-second the default with an explicit "resolve"). It could well be quite interesting. But for JavaScript, I think we're better off with the explicit `await`. -- T.J. [1]: http://www.ecma-international.org/ecma-262/7.0/index.html#sec