AngularJS:等待异步调用

时间:2013-10-08 14:02:44

标签: javascript angularjs synchronization

我无法理解AngularJS的承诺概念。

我有一个提供者:

var packingProvider = angular.module('packingProvider',[]);

packingProvider.provider('packingProvider',function(){
    return{
       $get: function($http){
           return{
              getPackings: function(){
                  $http.post('../sys/core/fetchPacking.php').then(function(promise){
                      var packings = promise.data;
                      return packings;
                  });
              }
           }
       }
   }
});

如您所见,这提供了一个方法getPackings(),它将返回一个对象

现在,如果我在主应用程序中使用它来接收数据,那么调用将是异步的,导致我不得不“等待”数据的问题:

var packings = packingProvider.getPackings();

console.log(packings); // undefined

如果不将进程重构到我的主控制器中,我该怎么做?

3 个答案:

答案 0 :(得分:7)

尝试

var packingProvider = angular.module('packingProvider',[]);

packingProvider.provider('packingProvider',function(){
    return{
       $get: function($http){
           return{
              getPackings: function(){
                  return $http.post('../sys/core/fetchPacking.php').then(function(response){
                      return response.data; // packings
                  });
              }
           }
       }
   }
});

然后

packingProvider.getPackings().then(function(packings){
    console.log(packings);
});

主要思想:您需要从getPackings函数返回promise对象。不确定你是否可以同步调用它,但这样做几乎绝对不是一个好主意。此外,如果您想在控制器上“填充”模型对象并用于双向绑定,则可以安全地分配promise对象,Angular将在数据通过时立即解析:

$scope.packings = packingProvider.getPackings();

<强>更新

从1.2.0-rc.3开始,承诺解包已被弃用(https://github.com/angular/angular.js/blob/master/CHANGELOG.md#120-rc3-ferocious-twitch-2013-10-14),因此上面的代码行不再导致双向绑定。

答案 1 :(得分:7)

您认为then方法中的返回值不会返回;它回来了。

在语句var packings = packingProvider.getPackings();中,返回值未定义,因为从$http返回的promise是异步的。这意味着调用$http.post无法完成,然后您的函数返回。在没有返回任何内容的JS函数中返回undefined。 post调用稍后完成并执行return packings;,无法返回。

getPackings方法应该直接从$http.post返回承诺。这样,任何想要使用此方法的代码都可以直接在promise上调用then,并按照需要的方式设置值。在控制器中,您可以将该承诺直接分配给$scope并在您的视图中使用它。这是一篇很好的帖子,解释了这个特殊功能:http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

顺便说一句,看起来你在那里有一个冗长的服务声明;有什么理由不把它缩短到这样的东西?

var module = angular.module('packing', []);

module.service('packing', function($http) {
  return {
    getPackings: function() {
      return $http.post('../sys/core/fetchPacking.php');
    }
  };
});

我对AngularJS比较陌生,但我没有看到所有输入都有任何好处。 (=

答案 2 :(得分:1)

有大量资源可以向您展示如何在jQuery中使用Deferreds / Promises。尝试搜索那些,这可能会帮助您克服这个障碍。 Afaik,AngularJS承诺与jQuery承诺相同。

使用类似这样的jQuery承诺:

var getPackings = function() { return $.get('../sys/core/fetchPacking.php'); };
var packings;
$.when(getPackings()).then(function(data){ packings = data; console.log(packings) });

请记住,jQuery ajax调用具有.done,.success等函数,它们将替换泛型Deferreds的.when()。then()函数。

在上面的jQuery方法中,您可以看到我们必须设置数据并将其输出到.then()函数中,因为您不能保证异步过程在其他任何地方完成。因此,理想情况下,您可以调用.then()函数中继续处理的任何函数,如下所示:

$.when(myAsyncFunc()).then(myAppCanContinue(dataReturnedByAsyncFunc));

Angular将遵循相同的逻辑。如果您了解上述内容,则应该更容易理解如何在Angular中实现此目的。另外,请查看这篇提供简单示例的文章:http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

为了让您的代码正常工作,您需要执行以下操作:

packingProvider.provider('packingProvider',function(){
    return{
       $get: function($http){
           return{
              getPackings: function(){
                  return $http.post('../sys/core/fetchPacking.php');
              }
           }
       }
   }
});
var packings = packingProvider.getPackings();

packings.then(function(data) { console.log(data)});