Chain Angular $http 调用正确吗?

Chain Angular $http calls properly?

几天来我一直在阅读有关 $q 和 promises 的内容,我似乎理解了它……有些理解。我在实践中有以下情况:

  1. 发起$http请求并检查是否可以进行后续调用。
  2. 如果第一次调用失败,return"no data",如果成功说可以调用,则进行第二次调用,如果不行- "no data" 再次。如果第二次调用成功,它 returns 数据,如果没有 - "no data"。大概是这样的(大致上,我简化了一般思路,所以不要担心这里的小错误):

            return $http.get (something)
                .then(function(allowedAccess){
                    if(allowedAccess){
                        return $http.get (somethingElse)
                            .then( function(result){return {data:result} },
                            function(error){return {data:"n0pe"} }
                        )
                    } else {
                        return {data:"n0pe"}
                    }
                },
                function(){ return {data:"n0pe"} });
    

有人告诉我在这里使用 $q。我真的不明白我会如何或为什么会。 $http 调用已经是承诺。

如果有办法让这个更干净,我没有看到。刚刚重新阅读这篇 post on the subject。本质上,我是不是遗漏了什么/有更好的方法吗?

编辑:也只需重新阅读 a tutorial on chaining promises - 它根本不处理呼叫失败。基本上将其发布为尽职调查。

编辑 2:这是对我所问理论的详细阐述,摘自第一篇文章:

This is a simple example though. It becomes really powerful if your then() callback returns another promise. In that case, the next then() will only be executed once that promise resolves. This pattern can be used for serial HTTP requests, for example (where a request depends on the result of a previous one):

这似乎是在谈论这样的链:

   asyncFn1(1)
    .then(function(data){return asyncFn2(data)})
    .then(function(data){return asyncFn3(data)})

所以,如果我理解正确的话 a)。不适用于我,因为我没有第三个功能。 b).如果我有三个函数将适用于我,因为虽然我在第一个 $http 请求中 运行 一个 if 语句,并且仅在 if 语句中我 return 另一个承诺。所以,理论上,如果我要链接三个异步函数,我需要将我的 if 语句放在一个 promise 中吗?

$q 将有助于减少这样的调用金字塔:

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

此博客 post - http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ - 提供了一种简洁的方式来发出多个 HTTP 请求。注意使用 $q 的更简洁的方法。如果您正在访问单个 HTTP 端点,那么使用您的方法就可以了。我会说,你有的也很好; $q 可能会在未来提供更大的灵活性。

博客 post 描述了使用 $q 时的服务,代码看起来更清晰。

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(...

我也是一个有承诺的初学者,所以对此持保留态度。

Promises 确实有助于编写异步调用的代码。换句话说,它们允许您以类似于编写一组同步调用(使用链式 .thens)的方式编写代码,就好像同步代码在 try/catch 块(使用 .catch)。

因此,想象一下您的 HTTP 调用被阻塞了 - 您的逻辑如下所示:

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;

你可以稍微简化一下:

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;

这将转化为异步版本:

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

至少,这是您在使用分支和异步调用编写代码时可以应用的推理。

我并不是说我提供的版本是最佳的或更短的 - 它 ,但是,由于单一错误处理。但是请注意,当您执行 .then(success, error) 时,它等同于之前异步操作的 try/catch - 这可能需要也可能不需要,具体取决于您的具体情况。

这就是我编写这类问题的方法:

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

是的,这与 New Dev 的回答非常相似,但我想强调将函数提取到它们自己的块中。这使整体代码更具可读性。