unhurried

コンピュータ関連ネタがほとんど、ときどき趣味も…

How to cope with Callback Hell #3 aa

This time I have researched aa which was introduced in Qiita (Japanese website). aa is another library like co and utilize Generator mechanizm to make it easier to wirite parallel ans serial flows. aa has some advantages to co, that is thunkify and promisify are included in the same package, and it has thunkifyAll and promisifyAll which enable affecting all the objects. However, aa doesn't have a function equivalent to co.wrap, so it is a little inconvenient to write a yieldable function which uses parallel and serial flows.

const aa = require('aa');

// An object which has a function whose argument is callback.
var callbackObject = {
  func: function(message, timeout, callback) {
    setTimeout(function() {
    console.log(message);
      callback(null, message);
    }, timeout);
  }
};

// aa.promisifyAll will apply promisify to the whole object.
// promisify converts a fucntion whose argument is callback to one returning a Promise.
// yeild can be applied to Promise in generator (yeildable).
var promisifiedObject = aa.promisifyAll(callbackObject);

// As with co when Generator (function*(){...}) is passed to aa function,
// aa will resume the process after the Promise is finished.
aa(function*() {
  console.log('--- aa start ---');
 
  // Process two functions parallely.
  // Specify Array or Object to yield to do a parallel process.
  var response = yield [
    promisifiedObject.funcAsync('aa two', 800),
    promisifiedObject.funcAsync('aa one', 600),
  ];
  console.log("response: " + JSON.stringify(response));

  // Process two function serially.
  yield promisifiedObject.funcAsync('aa three', 200);
  yield promisifiedObject.funcAsync('aa four', 400);
 
  // Call a function using aa (See below)
  yield wrappedFunction();

  console.log('--- aa end ---');

  // When return is called in Generator,
  // a function specified to aa.then() will be executed.
  return "Generator finished.";

  // When a reject function is called in any of Promises,
  // the fucntion which is specified in aa.error() will be 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);
});

// Since aa doesn't have a feature equivalent to co.wrap,
// we have to make a function which returns aa(function*(){}).
var wrappedFunction = function() {
  return aa(function* () {
    console.log('--- wrap start ---');

    var response = yield [
      promisifiedObject.funcAsync('wrap two', 800),
      promisifiedObject.funcAsync('wrap one', 600),
    ];
    console.log("wrap response: " + JSON.stringify(response));
    yield promisifiedObject.funcAsync('wrap three', 200);
    yield promisifiedObject.funcAsync('wrap four', 400);

    console.log('--- wrap end ---');

    return yield Promise.resolve(null);
  });
};

Result

$ node aa_generator.js
--- aa start ---
aa one
aa two
response: ["aa two","aa one"]
aa three
aa four
--- wrap start ---
wrap one
wrap two
wrap response: ["wrap two","wrap one"]
wrap three
wrap four
--- wrap end ---
--- aa end ---
--- then start ---
Generator finished.

Reference