-1

I want to combine the result of two asynchronouse function calls. I tried to get that as seperate functions.

$scope.showPage = function () {
    var base ="";
    var menu= "";
    service.getGUI('menu', function (reply) {
            if (reply.status === 200 && reply.data !== null) {                  
               menu = reply.data; 
            }
        });

    service.getGUI('base', function (reply) {
            if (reply.status === 200 && reply.data !== null) {                 
               base=reply.data;                 
        });

console.log("base:"+ base);
console.log("menu:"+ menu);
}

But the console output is not updating as expected. How can I execute is one by one and use the result of the first one in second function.

Nidheesh
  • 4,390
  • 29
  • 87
  • 150

3 Answers3

0

const asyncFunction = (x, cb) => setTimeout(cb.bind(null, x), 100 * Math.random())

// What you have
asyncFunction('Async 1', console.log)
asyncFunction('Async 2', console.log)

asyncFunction('Async 3', (x) => {
  console.log(x)
  asyncFunction('Async 4', console.log)
})
.as-console-wrapper { max-height: 100% !important; top: 0; }

As you can see Async 1/2 values are printed in a different order each time but Async 4 is always printed after Async 3.

Diego
  • 816
  • 7
  • 17
0

Your calls are both async so there is no consistency for what order the functions will finish in. You can use the promise reduce pattern to accomplish wait until both are resolved before accessing the data. While the promise reduce may not seem the best on the surface when you are dealing with 20+ async calls you will appreciate not having to continue nesting.

$scope.showPage = function () {
  var results = { base: "", menu: "" };

  ['menu', 'base'].reduce(function(acc, current) {
    return acc.then(new Promise(function(resolve, reject) => {
      service.getGUI(current, function (reply) {
        if (reply.status === 200 && reply.data !== null) {                  
           results[current] = reply.data; 
           resolve(results);
        } else {
           reject("error")
        }
      });
    }));
  }, Promise.resolve()).then(function(res) {
    console.log(res.menu, res.base);
  }).catch(function(e) { 
    console.log('errors have occured', e); 
  });
}
John Rodney
  • 175
  • 6
0

Convert the callback-based API to a promise-based API:

function getGUIpromise(item) {
    var deferredItem = $q.defer();
    service.getGUI(item, function (reply) {
        if (reply.status === 200 && reply.data !== null) {                  
            deferredItem.resolve(reply.data); 
        } else {
            deferredItem.reject("Error with getGUI "+item);
        };
    });
    return deferredItem.promise;
}

Then use $q.all to wait for the promises:

$scope.showPage = function () {
    var basePromise = getGUIpromise("base");
    var menuPromise = getGUIpromise("menu");

    $q.all({base: basePromise, menu: menuPromise})
    .then(function(result) {
        console.log("base:"+ result.base);
        console.log("menu:"+ result.menu);
    }).catch(function(error) {
        console.log(error);
    });  
};

Alternately if under-the-hood, the service.getGUI method uses a promise-based API, the original under-the-hood promise should be returned and used.

georgeawg
  • 48,608
  • 13
  • 72
  • 95