Chain Angular $http calls properly?

被刻印的时光 ゝ 提交于 2019-11-30 17:16:27

Promises really help with code composition of making async calls. In other words, they allow you to compose your code in a similar manner to how you would compose a synchronous set of calls (with the use of chained .thens) and as if it the sync code was in a try/catch block (with .catch).

So, imagine that your HTTP calls were blocking - the logic you have would look like so:

var allowedAccess, data;
try {
  allowedAccess = $http.get(something);

  if (allowedAccess){
    try{
      var result = $http.get(somethingElse);
      data = {data: result};
    } catch (){
      data = {data: "n0pe"};
    }
  } else {
    data = {data: "n0pe"};
  }
} catch (){
  data = {data: "n0pe"};
}
return data;

You could simplify it a bit:

var allowedAccess, result;
try {
  allowedAccess = $http.get(something);
  var result;
  if (allowedAccess) {
     result = $http.get(somethingElse);
  } else {
     throw;
  }
  data = {data: result};
} catch () {
   data = {data: "n0pe"};
}
return data;

And that would translate to the async version of:

return $http
          .get(something)
          .then(function(allowedAccess){
             if (allowedAccess){
               return $http.get(somethingElse);
             } else {
               return $q.reject(); // this is the "throw;" from above
             }
          })
          .then(function(result){
             return {data: result};
          })
          .catch(function(){
             return {data: "n0pe"};
          })

At least, this is the reasoning you could apply when composing code with branches and async calls.

I'm not saying that the version I presented is optimal or shorter - it is, however, more DRY because of a single error handling. But just realize that when you do .then(success, error) it is equivalent to try/catch over the previous async operation - this may or may not be needed depending on your specific circumstance.

This is how I would code this sort of problem:

// returns a promise that resolves some endpoint if allowed
function getDataWithAccess(allowed){
    return allowed ? $http.get(someEndpoint) : $q.reject();
}

// do something with data
function handleData(data){
    // do stuff with your data
}

// main chain
$http.get(accessCredEndpoint)
    .then(getDataWithAccess)
    .then(handleData)
    .catch(function(err){
        return { data: "n0pe" };
    });

Yes, this is very much like New Dev's answer, however I wanted to make a point of extracting the functions into their own blocks. This makes the overall code much more readable.

$q will help reduce pyramid of calls like this:

async-call1.then(...
  aysnc-call2.then(...

This blog post - http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ - offers a clean way of making multiple HTTP requests. Notice the cleaner approach using $q. In case you were hitting a single HTTP endpoint, using your method would have been just fine. I'd say, what you have is fine also; $q might allow greater flexibility in the future.

The blog post describes a service while using $q and the code looks cleaner.

service('asyncService', function($http, $q) {
  return {
    loadDataFromUrls: function(urls) {
      var deferred = $q.defer();
      var urlCalls = [];
      angular.forEach(urls, function(url) {
        urlCalls.push($http.get(url.url));
      });
      // they may, in fact, all be done, but this
      // executes the callbacks in then, once they are
      // completely finished.
      $q.all(urlCalls)
      .then(...

I am a beginner with promises also, so take this with a grain of salt.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!