1

Given an array which contains objects of type A and B, where B can be transformed to a set of A type objects, via an asynchronous call, which would be the best way of transforming the array into an all A objects array (transforming each B object in a set of corresponding A objects) and execute a callback when Bs are transformed?

    list = [A, B, A, B, A, A, B, A];

    function transform (B, callback) {
       //transform B type object into A type objects array [A, A, A].....
       callback([A, A, A]);
    }

    transformBObjectsIntoAObjects(list, callback) {
       // ?????????
      callback(list); // this should only be A type objects
    }
2
  • Do you use libraries like async or when? Commented Sep 22, 2014 at 12:03
  • @closure sure, the solution can also use async. Commented Sep 22, 2014 at 12:10

2 Answers 2

2

Well, you need to execute your final callbacks after all the callbacks from transformBtoList have returned a result. There are multiple ways to do it:

  1. Count how many callbacks you have passed away and decrement when they call back, and you know that you're finished when the counter has reached zero again.

    However, this is cumbersome, and there are libraries that help you with it:

  2. async.js is well-known and easy to use:

    function transform(B, callback) { … }
    function transformBObjectsIntoAObjects(list, callback) {
      async.map(list, function(X, cb) {
        if (X is B)
          transform(X, cb)
        else
          cb([X])
      }, function(results) {
        callback(concat(results))
      }
    }
    
  3. Promises (there are many implementations are a superior approach. They might be a bit more complex to understand, but have very nice properties and lead to nice & concise syntax. In your case, it would be

    function transform(B) { // no callback!
      // async:
        resolve([A, A, A]); // see docs of your promise library
      return promise;       // for exact reference
    }
    function transformBObjectsIntoAObjects(list) {
      return Promise.all(list.map(function(X) {
        return (X is B) ? transform(X) : Promise.resolve([X]);
      })).then(concat);
    }
    
Sign up to request clarification or add additional context in comments.

Comments

1

Here is a complete working example with async:

var async = require("async")

function A (id) {
  this.id = 'A' + id;
}

function B (id) {
  this.id = 'B' + id;
}

var list = [new A(1), new B(2), new A(3), new B(4)];

function transformBObjectsIntoAObjects (b, callback) {
   var ar = [], count = Math.random() * 5;
   for (var i = 1; i <= count; i++)
     ar.push(new A(b.id + "_" + i))
   return callback(null, ar);
}

async.map(list, function(arItem, cb) {

  return (arItem.constructor === B) ? transformBObjectsIntoAObjects(arItem, cb) : cb(null, arItem)

  }, function (err, arResult) {
    var flatAr = [].concat.apply([], arResult);
    console.log(flatAr);
  }
)

One such result (B parts are randomly generated) looks like:

[ { id: 'A1' }, { id: 'AB2_1' }, { id: 'AB2_2' }, { id: 'A3' }, { id: 'AB4_1' } ]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.