2013-10-08 221 views
11

我无法将自己的头围绕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 

我会怎么做没有重构过程进入我的主控制器?

+2

怎么样''getPackings''也返回''promise''? – Kita

回答

7

当您认为它的方法不会返回您的then方法中的返回值;它稍后会返回。

在语句var packings = packingProvider.getPackings();中,返回值未定义,因为从$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比较陌生,但在打字时没有看到任何好处。 (=

+0

谢谢迄今为止。我会认为,通过简单的服务选择提供商总是一个好主意,因为它具有更高的可配置性。在默认情况下选择提供商时是否有任何缺点? – user2422960

+1

大部分只是很多代码,你可能不需要。真的,这取决于你想要什么样的可配置性。你在设定值吗?为什么不给你的服务注入一个'value'或'constant'呢?如果你正在编写一个服务供图书馆使用,那么我可以使用'provider'调用,这样图书馆的消费者就不必知道你正在注入的这些神奇的值,但是否则直接的'service'会更简单。 –

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函数返回的承诺目标。不确定是否可以同步进行调用,但这样做几乎绝对不是一个好主意。

$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),所以上面的代码线将不会导致在两定向结合任何更多。

+1

忘了提及另一个关键点:你可以尽可能多地链接“then”:从“then”返回的值将被传递到随后的“then”作为参数 –

+0

谢谢,真的帮助我了 –

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()函数中,因为您无法保证异步过程在其他任何地方完成。所以最好你会打电话给任何功能的。那么()函数继续你的处理,像这样:

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

角是要遵循同样的逻辑。如果你了解上述内容,应该更容易理解如何在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)});