代码之家  ›  专栏  ›  技术社区  ›  VSO

Chain Angular$http调用正确吗?

  •  17
  • VSO  · 技术社区  · 11 年前

    我已经读了几天关于$q和承诺的书,我似乎有点理解它。我在实践中遇到以下情况:

    1. 发出$http请求并检查是否可以进行后续调用。
    2. 如果第一次调用失败,则返回“no data”,如果成功并表示可以进行调用,则进行第二次调用,如果没有,则再次返回“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:这是对我所问理论的详细阐述,摘自第一篇文章:

    这是一个简单的例子。如果您的then()回调返回另一个承诺,它就会变得非常强大。在这种情况下,下一个then()将仅在该承诺解决后执行。例如,此模式可用于串行HTTP请求(其中请求取决于前一个请求的结果):

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

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

    所以,如果我理解正确,这是a)。不适用于我,因为我没有第三个功能。b) 。如果我有三个函数,这将适用于我,因为当我在第一个$http请求中运行if语句时,只有在if语句中,我才能返回另一个承诺。所以,理论上,如果我有三个异步函数要链接,我需要将if语句放在promise中?

    3 回复  |  直到 11 年前
        1
  •  14
  •   New Dev    11 年前

    Promise确实有助于编写异步调用的代码。换句话说,它们允许您以类似于编写同步调用集的方式编写代码(使用链式 .then s) 就好像同步码在 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) 它相当于 尝试 / 接住 与之前的异步操作相比,这可能需要,也可能不需要,具体取决于您的具体情况。

        2
  •  8
  •   Matt Way    11 年前

    这就是我如何编码这类问题:

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

    是的,这很像新开发的答案,但我想强调将函数提取到它们自己的块中。这使得整个代码更加可读。

        3
  •  -1
  •   zedfoxus    11 年前

    $q将有助于减少这样的呼叫金字塔:

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

    此日志- http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ -提供了一种生成多个HTTP请求的干净方法。注意使用$q的更干净的方法。如果您到达了一个HTTP端点,那么使用您的方法就可以了。我想说,你拥有的也很好$q可能会在未来提供更大的灵活性。

    博客文章描述了使用$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(...
    

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