The second countermeasure of Callback Hell is using co. co is a library which utilizes Generator mechanism and make it easy to write serial and parallel flows.
const co = require('co'); const thunkify = require('thunkify') // a function which has a callback in its argument var callbackFunction = function(message, timeout, callback) { setTimeout(function() { console.log(message); callback(null, message); }, timeout); }; // thunkify converts a function with a callback to one returning a thunk. // yield can be applied to thunk in generator. (yeildable) var thunkifiedFunction = thunkify(callbackFunction); // a function which returns a Promise var promiseFunction = function(message, timeout) { return new Promise(function(resolve, reject){ setTimeout(function() { console.log(message); resolve(message); }, timeout); }); }; // When a Generator (function*(){...}) is passed to co, // co will proceed the process of the Generator until a yeild statement appear, // and resume the process after the Promise object is finished. co(function*() { console.log('--- co start ---'); // Process two functions in parallel. // Specify an array or an object to yeild. var response = yield [ thunkifiedFunction('co two', 800), promiseFunction('co one', 600), ]; console.log("response: " + JSON.stringify(response)); // Process two functions serially. yield thunkifiedFunction('co three', 200); yield promiseFunction('co four', 400); // Functions defined using co.wrap can be used in co generator. yield wrappedFunction(); console.log('--- co end ---'); // When return is called, co.then() is executed. return "Generator finished."; // When a reject function is called in one of Promise objects, // co.error() is executed. // yield Promise.reject("An error happened."); }).then(function(value){ console.log('--- then start ---'); console.log(value); }).catch((error) => { console.log('--- error start ---'); console.log(error); }); // Functions using co generator can be defined by using co.wrap. // They are also yieldable because they also return a Promise object. var wrappedFunction = co.wrap(function* () { console.log('--- co.wrap start ---'); var response = yield [ thunkifiedFunction('co.wrap two', 800), thunkifiedFunction('co.wrap one', 600), ]; console.log("co.wrap response: " + JSON.stringify(response)); yield thunkifiedFunction('co.wrap three', 200); yield thunkifiedFunction('co.wrap four', 400); console.log('--- co.wrap end ---'); return yield Promise.resolve(null); });
Result
$ node co_generator.js --- co start --- co one co two response: ["co two","co one"] co three co four --- co.wrap start --- co.wrap one co.wrap two co.wrap response: ["co.wrap two","co.wrap one"] co.wrap three co.wrap four --- co.wrap end --- --- co end --- --- then start --- Generator finished.