非$ q承诺在angularjs中解析后自动应用$ scope更改(触发器摘要)

时间:2014-09-23 00:40:34

标签: javascript angularjs promise angular-promise

假设你有:

function myPromise() {
  // using some promise lib other than $q, like Q or bluebird
  var defer = Q.defer();
  defer.resolve('John');
  return defer.promise;
}

然后你有类似的东西:

function foo() {
  return myPromise().then(function (name) {
    return name + ' Smith';
  });
}

foo().then(function (name) {
  $scope.$apply(function () { // or can use $timeout
    console.log('after foo');
    $scope.text = 'Hey ' + name;
  });
});

有没有办法修改foo,以便foo块之后的自动包装在$ scope中。$ apply()?即我们可以只有:

foo().then(function (name) {
  console.log('after foo');
  $scope.text = 'Hey ' + name;
  // $scope.$apply() is automatically called after this block is executed
});

我问的原因是我正在开发一个API,其中用户将进行多个这些foo调用,如果在foo promise结算后自动触发摘要周期,它将大大减少用户的代码。我知道我可以使用回调来实现这一点,但我希望有一种更简洁的方式来使用promises。

我的预感是解决方案在于将非$ q承诺包含在$ q承诺中......

2 个答案:

答案 0 :(得分:1)

目前Angular的结束无法做到这一点。从另一个方向来看,Q promise库也没有公开这个钩子。

所以,你有两个选择:

  • 覆盖所有Q非角度承诺的then方法,这将起作用,因为Q的结构如何,但有点危险,并且可能在Q的未来版本中中断(因此在升级时要小心)。 / LI>
  • 使用像Bluebird这样的承诺库,lets you use Angular seamlessly like you want没有任何问题与简短的代码段。使用Bluebird这个问题更简单

我强烈建议使用后者并使用允许您设置调度程序的promise库。它有更好的支持,并没有创造超额承诺。但是,如果您想在第一个方法中使用第一个方法:

var oldThen = Q.Promise.prototype.then; // reference `then` 
Q.Promise.prototype.then = function(){
    return oldThen.apply(this, arguments). // decorate
           then(function(value){
                $rootScope.$evalAsync(function(){}); // schedule digest
                return value; // keep value
           },function(err){
               $rootScope.$evalAsync(function(){}); // schedule digest
               return $q.reject(err); // keep rejection
           });
};

基本上,如果在完成后没有安排一个摘要,我们会在此处推迟每个Q调度摘要。关于它的工作原理,您可以阅读this question and answer

(信用通知 - 我从我参与的讨论中获取了上述代码。上面的大部分代码都是由我编写的,但有些是由Angular的杰夫克罗斯编写的,所以对他也很有信心)

答案 1 :(得分:0)

我能够通过将我的API函数包装在$ timeout块中来触发摘要周期,例如

function foo() {
  return $timeout(function () {
    return myPromise().then(function (name) {
      return name + ' Smith';
    });
  });
}