async/await -> await/async: a simpler, less error-prone async syntax

kai zhu kaizhu256 at gmail.com
Wed Dec 6 01:49:11 UTC 2017


you can avoid this entire debate by using trusty and simple callbacks instead.  here's real-world example of using a callback like you would async/await, to asynchronously test various states/scenarios for user-login in an app (using recursion to avoid callback-hell):

https://github.com/kaizhu256/node-swgg/blob/2017.7.24/test.js#L918 <https://github.com/kaizhu256/node-swgg/blob/2017.7.24/test.js#L918>

```js
local.testCase_userLoginXxx_default = function (options, onError) {
/*
 * this function will test userLoginXxx's default handling-behavior
 */
    var modeNext, onNext;
    modeNext = 0;
    onNext = function (error, data) {
        modeNext += 1;
        switch (modeNext) {
        case 1:
            // cleanup userJwtEncrypted
            delete local.userJwtEncrypted;
            // test userLogout's default handling-behavior
            options = {};
            local.userLogout(options, onNext);
            break;
        case 2:
            // validate error occurred
            local.assert(error, error);
            // test userLoginByPassword's 401 handling-behavior
            options = { password: 'undefined', username: 'undefined' };
            local.userLoginByPassword(options, onNext);
            break;
        case 3:
            // validate error occurred
            local.assert(error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 401);
            // validate userJwtEncrypted does not exist
            local.assert(!local.userJwtEncrypted, local.userJwtEncrypted);
            // test userLogout's 401 handling-behavior
            options = {};
            local.userLogout(options, onNext);
            break;
        case 4:
            // validate error occurred
            local.assert(error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 401);
            // validate userJwtEncrypted does not exist
            local.assert(!local.userJwtEncrypted, local.userJwtEncrypted);
            // test userLoginByPassword's 200 handling-behavior
            options = { password: 'secret', username: 'admin' };
            local.userLoginByPassword(options, onNext);
            break;
        case 5:
            // validate no error occurred
            local.assert(!error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 200);
            // validate userJwtEncrypted exists
            local.assert(local.userJwtEncrypted, local.userJwtEncrypted);
            // test persistent-session handling-behavior
            local.apiDict['x-test crudNullGet']._ajax({}, onNext);
            break;
        case 6:
            // validate no error occurred
            local.assert(!error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 200);
            // validate userJwtEncrypted exists
            local.assert(local.userJwtEncrypted, local.userJwtEncrypted);
            // test userLogout's 200 handling-behavior
            // test jwtEncoded's update handling-behavior
            options = { jwtEncrypted: local.jwtA256GcmEncrypt({ sub: 'admin' }) };
            local.userLogout(options, onNext);
            break;
        case 7:
            // validate no error occurred
            local.assert(!error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 200);
            // validate userJwtEncrypted exists
            local.assert(local.userJwtEncrypted, local.userJwtEncrypted);
            // test userLogout's 401 handling-behavior
            options = {};
            local.userLogout(options, onNext);
            break;
        case 8:
            // validate error occurred
            local.assert(error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 401);
            // test userLoginByPassword's 400 handling-behavior
            local.ajax({ url: '/api/v0/user/userLoginByPassword?password=1' }, onNext);
            break;
        case 9:
            // validate error occurred
            local.assert(error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 400);
            // test userLogout's invalid-username handling-behavior
            options = { jwtEncrypted: local.jwtA256GcmEncrypt({ sub: 'undefined' }) };
            local.userLogout(options, onNext);
            break;
        case 10:
            // validate error occurred
            local.assert(error, error);
            // validate statusCode
            local.assertJsonEqual(data.statusCode, 401);
            onError(null, data);
            break;
        }
    };
    onNext();
};
```

and here’s screenshot of setting a single-breakpoint to easily debug and step through all 10 asynchronous switch-statements in the callback.
you can reproduce the test-case in screenshot with this link: https://kaizhu256.github.io/node-swgg/build..beta..travis-ci.org/app/?modeTest=1&modeTestCase=testCase_userLoginXxx_default <https://kaizhu256.github.io/node-swgg/build..beta..travis-ci.org/app/?modeTest=1&modeTestCase=testCase_userLoginXxx_default>

-kai




> On Dec 6, 2017, at 6:38 AM, Alexander Jones <alex at weej.com> wrote:
> 
> > with the added bonus of transparently allowing sync functions to be converted to async functions without fundamentally affecting consumer calling code.
> 
> It does fundamentally affect calling code if the calling code reaches outside of its local variables. The state of the world around you might change any time you await and give control back to the event loop.
> 
> On Mon, 4 Dec 2017 at 19:16, Naveen Chawla <naveen.chwl at gmail.com <mailto:naveen.chwl at gmail.com>> wrote:
> Obviously. The whole point of this proposal is that awaiting async functions is automatically _implied_ inside an `autoasync` function, unless an async function is called with a `background` qualifier (which thereby makes it return its promise instead). The OP is right: this is a far less bug prone way to do async programming than `async` `await`, while offering all its functionality, with the added bonus of transparently allowing sync functions to be converted to async functions without fundamentally affecting consumer calling code.
> 
> For those who want to be able to do extensive async programming, having this in the language, and using it instead of `await` `async` throughout, is a no-brainer.
> 
> Of course, I am qualifying that it must be new keywords, not `await` `async` juggled like in the original post, but that wasn't the thrust of the proposal anyway.
> 
> On Mon, 4 Dec 2017 at 21:09 Isiah Meadows <isiahmeadows at gmail.com <mailto:isiahmeadows at gmail.com>> wrote:
> Am I misunderstanding something about this proposal that it's substantially any different from `.then` or immediately invoked async functions?
> ```js
> // Original
> await function foo() {
>     const bar = async baz()
>     use(bar)
> }
> 
> // What I'm reading
> function foo() {
>     ;(async () => {
>         const bar = await baz()
>         use(bar)
>     })()
> }
> function foo() {
>     try {
>         Promise.resolve(baz())
>         .then(bar => { use(bar) })
>     } catch (e) {
>         Promise.reject(e)
>     }
> }
> ```
> 
> 
> On Mon, Dec 4, 2017, 09:54 T.J. Crowder <tj.crowder at farsightsoftware.com <mailto:tj.crowder at farsightsoftware.com>> wrote:
> On Mon, Dec 4, 2017 at 2:37 PM, Bob Myers <rtm at gol.com <mailto:rtm at gol.com>> wrote:
> >
> > It turns out that this approach has a number of problems.
> > As a result, future versions of selenium will no longer support it.
> > Test writers will be asked to write `await` where needed.
> 
> Were there problems other than the complexity of maintaining the
> promise manager tool and issues with debuggability? Neither of those
> seems like it would be an issue with Steven's proposal...
> 
> (I just realized for the first time, Bob, that your initials are RTM.
> I love it. You should adopt Frank as a second middle name. ;-) )
> 
> -- T.J. Crowder
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <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 <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 <https://mail.mozilla.org/listinfo/es-discuss>
> _______________________________________________
> 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/20171206/5a788f23/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Screen Shot 2017-12-06 at 8.35.29 AM.png
Type: image/png
Size: 1533376 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171206/5a788f23/attachment-0001.png>


More information about the es-discuss mailing list