问题 AngularJS:等待异步调用


我无法理解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

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


11641
2017-10-08 14:02


起源

怎么样 getPackings 也回来了 promise? - Kita


答案:


你的回报值 then 当你认为它时,方法不会返回;它回来了。

在声明中 var packings = packingProvider.getPackings(); 返回值是未定义的,因为从中返回了promise $http 是异步的。这意味着打电话给 $http.post 发生, 没有完成,然后你的函数返回。在没有返回任何内容的JS函数中返回undefined。该 post 调用稍后完成并执行 return packings; 哪个回到了无处。

getPackings 方法应该可以从中返回承诺 $http.post 直。这样,任何想要使用此方法的代码都可以调用 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比较陌生,但我没有看到所有输入都有任何好处。 (=


7
2017-10-08 14:20



非常感谢你到目前为止。我认为,通过简单的服务选择提供商总是一个好主意,因为它具有更高的可配置性。在默认情况下选择提供商时是否有任何缺点? - user2422960
主要是你可能不需要的很多代码。真的,这取决于你想要什么样的可配置性。你在设定价值吗?为什么不注射一个 value 或者a constant 而是进入你的服务?如果您正在编写要在库中使用的服务,我可以看到使用 provider 打电话让图书馆的消费者不必知道你注入的这些神奇的价值,而不是直接的 service 会更简单。 - D. Hayes


尝试

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();

UPDATE

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


7
2017-10-08 14:16



忘了提一个关键点:你可以随意链接“then”:从“then”返回的值将作为参数传递给结果“then” - Konstantin K
谢谢,真的帮帮我了 - Tim Castelijns


有大量资源可以向您展示如何使用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)});

1
2017-10-08 14:45