使用AngularJS链式处理承诺

26

我有一个叫做paymentStrategy的服务被注入到我的控制器中。

$scope.buy = function() {
  paymentStrategy.buy()
    .then(function(response) {

  }
}

这个支付策略的购买方法会触发多个需要按顺序调用的方法。当buy()中的所有方法都完成后,需要调用then()。

这可能很琐碎,但我对Angular还比较陌生。

目前,buy().then()在init()方法之后立即触发。我感觉我们需要将所有这些方法放入一个promise数组中,并应用$q.all()。

任何帮助或建议都将不胜感激。

angular.module('deps-app.payment.services', []).
  factory('paymentStrategy', function($q) {

 var deferred = $q.defer();
 var ITEM_TO_PURCHASE = "test.beer.managed";
 var promises = [];

 var handlerSuccess = function(result) {
      deferred.resolve(result);
  };

 var handlerError = function(result) {
      deferred.reject(result);
  };

 _init = function() {

     inappbilling.init(handlerSuccess, handlerError, { showLog:true }); 
     return deferred.promise;
    }

  _purchase = function() {
        inappbilling.buy(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
        return deferred.promise;
  }

  _consume = function() {
        inappbilling.consumePurchase(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
        return deferred.promise;
  }

return  {

     buy: function() {

      _init();
        .then(_purchase());
        .then(_consume());  

      return deferred.promise;                    
    }

 }
});

1
所有与应用内购买相关的方法,如init、buy和consumePurchase,是否都返回Promise? - Chandermani
听起来不错,但您能否请澄清如何做到这一点? - Florent Valdelievre
那是对你弗洛伦特的问题。你代码的问题在于你在init回调和其他回调中都解决了promise,但你需要在调用resolve之前等待所有调用完成。 - Chandermani
前两个参数handlerSuccess和handlerError是回调函数,当方法(init、buy和consumePurchase)完成时会调用它们。例如,只有在从init(...)中调用了handlerSuccess后才需要调用_purchase()。只有在从purchase(...)中调用了handlerSuccess后才需要调用_consume()。 - Florent Valdelievre
2个回答

57

如果您需要在Angular中按顺序链接承诺,可以简单地从一个承诺返回到另一个:

callFirst()
.then(function(firstResult){
   return callSecond();
})
.then(function(secondResult){
   return callThird();
})
.then(function(thirdResult){
   //Finally do something with promise, or even return this
});

如果你想将所有这些作为 API 返回:

function myMethod(){
   //Return the promise of the entire chain
   return first()
           .then(function(){
               return second();
           }).promise;
}

我对 Promise 和 Angular 都很陌生。这里的第一个 then 返回第二个 then 的调用,但它返回的是方法,实际上第二个 then 以值作为参数。我只懂 C,所以不太确定。 - santhosh
1
如此简单而又强大!谢谢。在阅读了您的帖子之后,我才明白我该做什么。我找到的所有其他示例都太复杂了。 - tarekahf
这是正确的方法。'return' 是必需的,否则这将无法工作。 - Leo Huang

20

将所有方法都变成原子操作,通过添加它们自己的Promise实现。在你的代码中,第一个resolve将完成整个请求。

如果方法有自己的Promise,你可以轻松地链式调用它们。

angular.module('deps-app.payment.services', []).factory('paymentStrategy', function($q) {
var ITEM_TO_PURCHASE = "test.beer.managed";

_init = function() {
  return $q(function (resolve, reject) {
    inappbilling.init(resolve, reject, { showLog: true }); 
  });
};

_purchase = function() {
  return $q(function (resolve, reject) {
    inappbilling.buy(resolve, reject, ITEM_TO_PURCHASE);  
  });
};

_consume = function() {
  return $q(function (resolve, reject) {
    inappbilling.consumePurchase(resolve, reject, ITEM_TO_PURCHASE);
  });
};

return  {
  // In this case, you don't need to define a additional promise, 
  // because placing a return in front of the _init, will already return 
  // the promise of _consume.
  buy: function() {    
    return _init()
      .then(_purchase)  
      // remove () from inside the callback, to pass the actual method 
      // instead the result of the invoked method.
      .then(_consume);      
  }    
};

});


非常感谢您的帮助,非常感激。在接受之前有一个问题。似乎在buy()方法中它从未进入then(..)。这样做是一个好方法吗?: _init() .then(_consumeAll) .then(_purchase) .then(_consume) .then(deferred.resolve) - Florent Valdelievre
啊,我的错误。现在请检查。 - Konstantin Krass
1
使用$q.defer()几乎总是不好的做法,并且这种情况也不例外。通过像_init = function() { return $q(function(resolve, reject) { inappbilling.init(resolve, reject, { showLog: true }); }); };这样做,可以简化这三个函数中的每一个函数,它将返回所需的promise。理想情况下,inappbilling上的方法应该返回promise(由您的_init等方法简单地返回),但我想这可能不是您要做出的决定。 - Sean the Bean
@Sean the Bean 是正确的。在2014年,这对我来说是唯一正确的答案,直到我发现了 return $q. 例程。 - Konstantin Krass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接