Skip to content

Instantly share code, notes, and snippets.

@dsathyakumar
Last active April 26, 2016 12:27
Show Gist options
  • Save dsathyakumar/565fec3bac17c50c45cba492dd9803c7 to your computer and use it in GitHub Desktop.
Save dsathyakumar/565fec3bac17c50c45cba492dd9803c7 to your computer and use it in GitHub Desktop.
Moving from async JS to ES6 promises

Moving (or) Converting from Async JS to ES6 Promises (Native)

The following summarises the learnings of migrating from the async promises module to ES6 promises, with a simple sample.

Async is a library containing a bunch of async utility functions like

  • async.parallel : To execute a bunch of async tasks in parallel.
  • async.waterfall: To execute a bunch of async tasks sequentially.

####The example had a combo of both:

The example below uses an express APP to create a server & uses the Async JS module with it.

var app = express();

Async.waterfall([
    Async.parallel.bind(Async, {
        init: function initStartup(next) {
            app.once('start', function () {
                next();
            });
        },
        config: function loadConfig(next) {
            //> read entries from a config file
            require('./src/config').onConfigured(function (config) {
                next(null, config);
            });
        }
    }),
    function start(ctx, next) {
        listen(ctx.config, next);
    }
], function started() {
    if (process.send) {
        process.send('online');
    }
    console.log('Server ready');
});



function listen(config, next) {
    var tasks = [];
    //> app uses Kraken JS
    var ssl = app.kraken.get('ssl');
    //Running HTTPS server on 8443 in Development Env
    if(ssl && env.isDev()) {
        tasks.push(function startSSL(next) {
            var sslServer = https.createServer(ssl, app);
            sslServer.listen(process.env.SSLPORT || 8443, function () {
                console.log('Application(HTTPS) Listening on port ', sslServer.address().port);
                next();
            });
        });
    } else {
        //Running additional port 8082 in Non-DEV
        tasks.push(function startSSL(next) {
            var sslport = process.env.SSLPORT || 8082;
            app.listen(sslport, function () {
                console.log('Application(HTTP) Listening on port ' + sslport);
                next();
            });
        });
    }

    tasks.push(function startNonSSL(next) {
        // non-secure port
        var port = config.port;
        app.listen(port, function () {
            console.log('Application(HTTP) Listening on port ' + port);
            next();
        });
    });

    Async.parallel(tasks, next);
}

The above code in ES6 becomes:

The above piece of code is re-written in ES6 makes use of

  • ES6 Promises,
  • const,
  • Block Scoping,
  • usage of let for block scoping &
  • ES6 Arrow functions that replace Anonymous functions
var app = express();

//> wrapping an async Task within a new Promise() - ES6 feature
var asyncTask_1 = new Promise((resolve, reject) => {
    //> promise is in pending state until it gets resolved within this block
    app.once('start', () => {
        //> just resolving it with a param
        resolve('success');
    });
});

//> wrapping an async Task within a new Promise() - ES6 feature
var asyncTask_2 = new Promise((resolve, reject) => {
    //> promise is in pending state until it gets resolved within this block
    require('./src/config').onConfigured((config) => {
        resolve(config);
    });
});

//> execute the two above mentioned async Tasks in parallel, but do sequential operations after both are resolved - ES6 feature
//> Promise.all - equivalent of Async.parallel - ES6 feature
//> every .then() following this is a sequential task. It takes a param called values which is an array of results
//> - equivalent of Async.waterfall
Promise.all([asyncTask_1, asyncTask_1])
.then(
    (values) => { //> success handler of then
        //> upon success of previous parallel tasks, do the next sequential async task
        //> Even for this async Task, the promise is in pending state until it gets resolved within this block
        new Promise((resolve, reject) => {
            //> result2 contains the result of asyncTask_2
            //> promise resolution for the current promise, happens in listen
            listen(values[1], resolve, reject);
        });
    },
    (error) => { //> failure handler of then
        console.log(error);
        //> promise resolution is done instantaneously to reject for error
        //> if not rejected, it will not progress in case of an error
        new Promise((resolve, reject) => {
            reject();
        });
    }
).then( 
    (values) => { //> success handler for then
        if (process.send) {
            process.send('online');
        }
        console.log('Server ready');
    },
    (error) => { //> failure handler for then
        console.log(error);
    }
);

//> re-writing listen() in ES6
function listen(config, resolve, reject) {
    //> define a constant - ES6 feature
    //> app uses Kraken JS
    const ssl = app.kraken.get('ssl');
    //> define a block scope - ES6 feature
    {
        let async_1; // block scope variable - ES6 feature
        
        //> Running HTTPS server on 8443 in Development Env
        if (ssl && env.isDev()) {
            
            //> Async operation wrapped in a promise
            async_1 = new Promise((resolve, reject) => {
                const sslServer = https.createServer(ssl, app);
                sslServer.listen(process.env.SSLPORT || 8443, () => {
                    console.log('Application(HTTPS) Listening on port ', sslServer.address().port);
                    resolve();
                });
            });
        } else {
            
            //> Running additional port 8082 in Non-DEV
            //> Async operation wrapped in a promise
            async_1 = new Promise((resolve, reject) => {
                const sslport = process.env.SSLPORT || 8082;
                app.listen(sslport, () => {
                    console.log('Application(HTTP) Listening on port ' + sslport);
                    resolve();
                });
            });
        }
        
        //> block scoped variable containing an async operation wrapped in a promise
        let async_2 = new Promise((resolve, reject) => {
            // non-secure port
            const port = config.port;
            app.listen(port, () => {
                console.log('Application(HTTP) Listening on port ' + port);
                resolve();
            });
        });

        //> execute all async operations in parallel - equivalent of Async.parallel
        //> Get their values, if the success block is invoked,
        //> resolve the caller
        Promise
            .all([async_1, async_2])
            .then(
                (values) => {
                    resolve(); //> using the arguments resolve - that was passed into listen()
                },
                (error) => {
                    console.log(error);
                    reject(); //> using the arguments reject - that was passed into listen()
                }
            ); //> end of then
    } //> end of block scope
} //> end of listen()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment