简体   繁体   中英

Javascript asynchronous calls chaining

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
    }

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); } 

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' } ]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM