Overview

Have you also recently upgraded your project from Node.js V6 LTS to Node.js V8 LTS (available since October 2017)?

A few good reasons to upgrade are:

  • To keep in sync with the latest LTS release;
  • To be able to use the powerful ES2017 async await operators in Node.js V8 LTS so you can finally write cleaner asynchronous source code;

 

Coroutines in Node.js V6 LTS

The golden pattern to write asynchronous source core in the previous release Node.js V6 LTS was to use Promises and Coroutines (which comes with the Bluebird library). Coroutines are, in short, generator functions that yield promises.

Note that you could use a transpiler in Node.js V6 LTS to support async await but I’m in principle against using transpilers in a Node.js server project.

 

Convert Coroutines to ES2017 async await

We are now ready to start using the async await operators, and more importantly get to rid off the coroutines logic of the Bluebird library.

Note that I’m not against using external libraries, but I prefer to use the same features within Node.js core if they are available.

So how do you convert coroutines/yield into async/await? The effort is remarkably simple.

You just need 2 code changes for each coroutine:

  1. Replace Promise.coroutine(function* () with async function () {
  2. Replace = yield with = await

Note that no changes are needed in the try catch throw logic (thank God!).

A full example so you can compare the old and the new version:


function usingCoroutineYield() {
    Promise.coroutine(function* () {
        console.log('usingCoroutineYield(): begin');
        let objResponse;

        objResponse = yield doubleAfterSeconds(2);
        console.log('usingCoroutineYield() CY#1 | 2s | yielded objResponse: ', objResponse);

        objResponse = yield Promise.resolve(100);
        console.log('usingCoroutineYield() CY#2 | no delay | yields objResponse: ', objResponse);

        console.log('usingCoroutineYield(): end');
    })(); // IIFE Immediately Invoked Function Expression
}

function usingAsyncAwait() {
    (async function () {
        console.log('usingAsyncAwait(): begin');

        let objResponse;

        objResponse = await doubleAfterSeconds(5);
        console.log('usingAsyncAwait() AA#1 | 5s | awaited objResponse: ', objResponse);

        objResponse = await 200;
        console.log('usingAsyncAwait() AA#2 | no delay | awaited objResponse: ', objResponse);

        console.log('usingAsyncAwait(): end');
    })(); // IIFE Immediately Invoked Function Expression
}

 

What about ESLint?

The configuration of ESLint must be changed so that it supports ES2017. I prefer to use .eslintrc.json files for that. Pay attention to the property “ecmaVersion”: 2017

A working example file .eslintrc.json must exist in the root of your Node.js project directory:


    {
    "root": true,
    "env": {
        "browser": true,
        "es6": true,
        "jquery": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 2017
    },
    "globals": {
        "debug": true
    },
    "rules": {
        "indent": [
            "error",
            4
        ],
        "linebreak-style": "off",
        "no-console": "off",
        "no-unused-vars": "warn",
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ]
    }
}

 

A runnable Github Node.js project with examples of coroutines/yield and async/await.

I have developer a small example project so you compare & debug both variations. It also gives you valuable insights in what code is executed when exactly.

Procedure:


git clone https://github.com/cvrolf/blog-asyncawait-coroutineyield-2017.git
cd blog-asyncawait-coroutineyield-2017
npm install
grunt
npm run start

OUTPUT:


> blog-asyncawait-coroutineyield-2017@1.0.0 start blog-asyncawait-coroutineyield-2017
> node ./index.js
environment:
  process.env.NODE_ENV: development
Reached: section TIMER
Reached: section MAIN
usingCoroutineYield(): begin
usingAsyncAwait(): begin
Reached: section END
  timer @ 1000ms
  timer @ 2000ms
usingCoroutineYield() CY#1 | 2s | yielded objResponse:  4
usingCoroutineYield() CY#2 | no delay | yields objResponse:  100
usingCoroutineYield(): end
  timer @ 3000ms
  timer @ 4000ms
usingAsyncAwait() AA#1 | 5s | awaited objResponse:  10
usingAsyncAwait() AA#2 | no delay | awaited objResponse:  200
usingAsyncAwait(): end
  timer @ 5000ms
  timer @ 6000ms
  timer @ 7000ms
  timer @ 8000ms
  timer @ 9000ms
 stopping the interval timer

 

Related Skills

 

References

 

Next Steps

Does it not work for you? Please make the required changes and let me know so we can share it with the community 🙂 @rolfhuijbrechts

Tagged with →