Does async/await solve a real problem?

Jeff Morrison lbljeffmo at gmail.com
Thu Sep 11 09:59:19 PDT 2014


On 9/11/14, 10:22 AM, Florian Bösch wrote:
> A -> B -> C -> D -> E changes to
>
> A -> B -> C -> D -> async E and causes
>
> A await -> B await -> C await -> D await -> async E
>
> And of course if A, B, C or D is used anywhere else it percolates 
> trough the entire call graph.
Sort of true, but this is no worse than the status quo.

function A() { return B(); }
function B() { return C(); }
function D() { return D(); }
function E() { return 42; } -> function E() {  return new 
Promise(function(res, rej) { res(42); }); }

I said "sort of" above because it's also worth pointing out that, in 
some cases, outer plain functions can still consume async functions 
without needing to themselves become async. The case arises where the 
result of the outer plain function doesn't depend on the async result of 
the inner function. Many cases don't apply here, but it's worth pointing 
out to show that consumption of async functions isn't *always* stack-viral:

function add(a, b) {
   var logSuccess = log('adding ' + a + ' and ' + b);
   if (!logSucces) {
     console.warn('log failed!');
   }
   return a + b;
}

function log(msg) {
   return logger.syncAppend(msg);
}

changes to

function add(a, b) {
   log('adding ' + a + ' and ' + b).catch(function(res) {
     console.warn('log failed!');
   }).done();

   return a + b;
}

async function log(msg) {
   return logger.asyncAppend(msg);
}

-Jeff
>
> Trying to protect people from interlaved code execution effects is 
> noble. But doing so by introducing a rote thing to type everytime you 
> change the code somewhere underneath is wrong. It's wrong because it 
> breaks logic isolation, it becomes impossible to change part of the 
> library/utiity code without this change affecting all code that uses 
> it. This guarantees that it doesn't happen in practice, because it's 
> too painful to do. It requires the code, that uses other code, to know 
> about the internal behavior of that code.
>
> If say, I'd propose a semantic that required you to write "foo" in the 
> code, but just for those pieces of code that contain mentions of 
> "bar", or that reference code that contains "bar" to the Nth degree, 
> you'd accuse me of trying to introduce a purposefully unusable 
> feature. How is await/async not an unusable feature?
>
>
>
> On Thu, Sep 11, 2014 at 4:00 PM, Mark S. Miller <erights at google.com 
> <mailto:erights at google.com>> wrote:
>
>     On Thu, Sep 11, 2014 at 6:20 AM, Florian Bösch <pyalot at gmail.com
>     <mailto:pyalot at gmail.com>> wrote:
>
>         await has also another problem in that if somewhere, deep down
>         the call stack, something is intending to do async, then up
>         the entire call stack everywhere you've got to insert await.
>         It's a bit of a headache for code maintenance (hello bicycle
>         repair man jam session), and it's also fairly unfriendly for
>         library authors.
>
>         There is a solution to that problem, which is not using
>         generators if you'd want co-routines. If you want co-routine
>         like behavior, please implement co-routines (and you can prop
>         whatever scheduling/managing on top of that).
>
>         An argument has been made in earlier discussions on that
>         topic, that JS VMs can't deal with co-routines (garbage
>         collection, DOM, whatever). But surely, if the VM can support
>         generators/continuations, it could support full co-routines.
>
>
>     VM issues are not the argument against coroutines or deep
>     generators. The issue is that unpredictable interleaving makes
>     reasoning about invariants much too difficult. Without these, we
>     have an important guarantee: When f synchronously calls g, the
>     only side effects that might have occurred by the time g returns
>     to f are those g might have caused. Thus, these are the only side
>     effect possibilities that f must worry about.
>
>     See section 18.3 of
>     <http://www.erights.org/talks/thesis/markm-thesis.pdf> and replace
>     postfix diagonal uparrow with prefix "await". In ES7 the example
>     would be
>
>         async function foo() { return bar(await getint(), y()); }
>         ... await foo() ...
>
>     The net effect is like co-routines, except that the placement of
>     "async" and "await" -- like the diagonal uparrow in the text --
>     marks the places where interleaving might occur. This is as close
>     to coroutine support as we should ever come.
>
>
>
>         I'd recommend python's greenlet as an outstanding
>         implementation of a co-routine interface that includes
>         basically everything one could wish from it. I'd not consider
>         python 3's "asyncio" a proper co-routine implementation (i.e.
>         it's the same generator/await hack as is being discussed here).
>
>         On Thu, Sep 11, 2014 at 3:05 PM, Kevin Smith
>         <zenparsing at gmail.com <mailto:zenparsing at gmail.com>> wrote:
>
>             Also, see
>             https://github.com/lukehoban/ecmascript-asyncawait/issues/14
>             for previous discussion.
>
>             On Thu, Sep 11, 2014 at 8:42 AM, Domenic Denicola
>             <domenic at domenicdenicola.com
>             <mailto:domenic at domenicdenicola.com>> wrote:
>
>                 There are several problems solved by async/await
>                 instead of twisting generators:
>
>                 1. What if you wanted to use generators for lazy
>                 sequences (iterables), instead of asynchronicity? If
>                 your framework assumes all generators are for async,
>                 you lose the original use case of generators.
>
>                 2. Say what you mean. `function*` and `yield` mean
>                 something very different from `async function` and
>                 `await`, similar to how `Subclass.prototype =
>                 Object.create(Superclass.prototype);
>                 Subclass.prototype.constructor = Subclass` is
>                 different from `class Subclass extends Superclass`.
>
>                 3. Operator precedence. You can do `await a + await b`
>                 to mean `(await a) + (await b)`, but `yield a + yield
>                 b` means `yield (a + (yield b))`.
>
>                 4. Ability to produce promise-returning functions
>                 without buying into a specific framework that
>                 interprets generators in a certain way. E.g., you
>                 could use `async function f() { return 5; }` to return
>                 a promise for 5, which people can consume with
>                 `f().then(v => ...)`. If you try to do `function* f()
>                 { return 5; }` you will get an iterable, which is not
>                 understood to be asynchronous. (Hopefully my use of
>                 `return 5` for brevity instead of more complex code
>                 does not confuse this point for you.)
>
>                 As for stack traces, long stack trace support is a
>                 debugging feature, and the fact that `yield*` gets
>                 them right now doesn't mean that `await` won't get
>                 them in the future.
>
>                 -----Original Message-----
>                 From: es-discuss
>                 [mailto:es-discuss-bounces at mozilla.org
>                 <mailto:es-discuss-bounces at mozilla.org>] On Behalf Of
>                 Jeswin Kumar
>                 Sent: Thursday, September 11, 2014 11:46
>                 To: es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>                 Subject: Does async/await solve a real problem?
>
>                 Looking at my project (in which asynchronous calls are
>                 entirely done via generators), I can't see how
>                 async/await would simplify code for end-users like me
>                 (application programmers).
>
>                 End users write the spawn()/Q.async()/co() wrapper *at
>                 most* one single time in an application:
>                 1. When using a framework like say koajs, you don't
>                 have to write it even once.
>                 2. While not using a framework, you'd have to use the
>                 wrapper one single time in say, the main.js file.
>
>                 To use the example at
>                 http://wiki.ecmascript.org/doku.php?id=strawman:async_functions
>
>                 async function chainAnimationsAsync(elem, animations)
>                 { CODE; } is just function chainAnimationsAsync*(elem,
>                 animations) { same CODE; } when flow control is done
>                 by a framework or at the entry point to your
>                 application. spawn() isn't needed.
>
>                 I can't see how this will reduce application's code
>                 even a little. So my question is, is async/await needed?
>
>
>                 One more question
>                 --------------------------
>                 1. yield is practically very difficult to use in a
>                 project because you don't get proper stack traces (at
>                 least with the current flow control libraries). You'd
>                 only see the last call which threw the error, and then
>                 functions from the flow control library immediately
>                 below that. I suppose the generators leading up to the
>                 erring generator are all suspended and wouldn't be on
>                 the stack frame chain.
>
>                 2. yield* generator delegation solves this problem,
>                 you get real stack traces. I was able to get full
>                 stack traces simply by replacing all yield X() with
>                 yield* X()
>
>                 example code as in: https://github.com/chopachom/syncio
>
>                 So if there are valid use-cases for adding async/await
>                 to JS, shouldn't it be based on how yield* works
>                 rather than yield?
>
>                 -- Jes
>
>                 The Fora Project is coming...
>                 https://github.com/jeswin/fora
>                 _______________________________________________
>                 es-discuss mailing list
>                 es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>                 https://mail.mozilla.org/listinfo/es-discuss
>                 _______________________________________________
>                 es-discuss mailing list
>                 es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>                 https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>             _______________________________________________
>             es-discuss mailing list
>             es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>             https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>         _______________________________________________
>         es-discuss mailing list
>         es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>         https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>
>     -- 
>         Cheers,
>         --MarkM
>
>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140911/2b5ef4c0/attachment-0001.html>


More information about the es-discuss mailing list