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
}
-
Do you use libraries like async or when?closure– closure2014年09月22日 12:03:48 +00:00Commented Sep 22, 2014 at 12:03
-
@closure sure, the solution can also use async.maephisto– maephisto2014年09月22日 12:10:31 +00:00Commented Sep 22, 2014 at 12:10
2 Answers 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:
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); }
Comments
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' } ]