Reputation: 5182
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
}
Upvotes: 1
Views: 85
Reputation: 7452
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' } ]
Upvotes: 1
Reputation: 664164
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:
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:
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))
}
}
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);
}
Upvotes: 2