Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS $q.all & multiple $q.defer

Even though I have managed to make my code work, there is something I don't understand. The following piece of code functions correctly:

socket.on('method', function() {
    var payload = {
      countrycode: '',
      device: ''
    };
    var d1 = $q.defer();
    var d2 = $q.defer();
    $q.all([
      geolocation.getLocation().then(function(position) {
        geolocation.getCountryCode(position).then(function(countryCode){
          payload.countrycode = countryCode;
          d1.resolve(countryCode);
        });
        return d1.promise;
      }),
      useragent.getUserAgent().then(function(ua) {
        useragent.getIcon(ua).then(function(device) {
          payload.device =  device;
          d2.resolve(device);
        });
        return d2.promise
      })
    ]).then(function(data){
      console.log(data); //displays ['value1', 'value2']
    })
  });

Is there a better way of achieving this? Before I had only one deferred variable, i.e. varvar deferred = $q.defer(); but that way the .then() function returned an object with double the results.

So the few question I have are:

  1. Do I need multiple $q.defer vars?
  2. Is the above the best way to wait for two async calls to finish and populate the payload object?
like image 412
Tamas Avatar asked Mar 04 '14 11:03

Tamas


2 Answers

socket.on('method', function() {
    var payload = {
      countrycode: '',
      device: ''
    };
    geolocation.getLocation()
    .then(function(position) {
      return geolocation.getCountryCode(position);
    })
    .then(function(countryCode) {
      payload.countrycode = countryCode;
      return useragent.getUserAgent();
    })
    .then(function(ua) {
      return useragent.getIcon(ua);
    })
    .then(function(device) {
      payload.device =  device;
      console.log(data); //displays ['value1', 'value2']
    });
});

read the promise chaining part

like image 132
wayne Avatar answered Oct 04 '22 03:10

wayne


You could always separate your code into smaller semantic blocks like so:

getCountryCode = function() {
  var d = $q.defer();
  geolocation.getLocation()
  .then(function(position) {
    return geolocation.getCountryCode(position)
  })
  .then(function(countryCode) {
    d.resolve(countryCode);
  })
  .fail(function(err) {
    d.reject(err);
  })
  return d.promise;
};

getDevice = function() {
  var d = $q.defer();
  useragent.getUserAgent()
  .then(function(ua) {
    return useragent.getIcon(ua)
  })
  .then(function(device) {
    d.resolve(device);
  })
  .fail(function(err) {
    d.reject(err);
  });
  return d.promise;
}

That will shorten your actual parallel call ($q.all) quite a bit:

socket.on('method', function() {
  $q.all([getCountryCode(), getDevice()])
    .spread(function(countryCode, device) {
      var payload = {
        countryCode: countryCode,
        device: device
      };
      // ... do something with that payload ...
    });
});
like image 45
Tharabas Avatar answered Oct 04 '22 02:10

Tharabas