是否有一种简单的方法可以将成功调用返回到$ q.all而无需创建$ q.defer()变量?

时间:2014-05-21 10:43:33

标签: javascript angularjs angular-promise

我的应用程序有许多同步和异步(执行$ http调用)方法。在 控制器我有这样的代码:

$q.all([
    asyncMethod1(),
    syncMethod1()
])
.then(function (results) {

即使我没有必要等待syncMethod1(),我把它放在$ q.all里面以保持简单并允许我 如果我将来想要将方法更改为异步。

对于同步功能,我这样称呼它们:

var syncMethod1 = function () {
    var defer = $q.defer();
    var abc = 99;
    defer.resolve({
        data1: abc,
        data2: 123
    });
    return defer.promise;
};

我想知道的是,如果有一种方法可以让同步方法返回$ q.all数据但没有我的 需要创建一个defer变量然后返回defer.promise?试着让同步方法变得简单 尽可能。

3 个答案:

答案 0 :(得分:1)

$q.all即使没有记录,也可以采用普通值,而不仅仅是promises(它会自动转换它们)。您的同步方法应该只是

return {
    data1: 99,
    data2: 123
};

这是最简单的事情(并且可以在真正的同步上下文中使用)。


  

如何在不使用繁琐的延迟的情况下从值中做出承诺?

您可以使用$q.when

return $q.when({
    data1: 99,
    data2: 123
});

如果该值不是承诺,则将返回一个尽快使用该值解析的承诺。请注意,这必然会在您的代码中引入异步,因此它不再是syncMethod

答案 1 :(得分:1)

TL; DR:是的,只需从同步方法返回正常值,并在$q.all中将它们用作输入参数。它会正确处理它们。

答案很长

如果我们查看$q.all的角度代码,我们会在this line看到输入参数的处理方式:

 function all(promises) {
     ....
     forEach(promises, function(promise, key) {
         ....
          ref(promise).then(function(value) {

因此每个参数都传递给ref函数defined at this lineref接受一个参数,如果它是一个承诺它会返回它

 if (value && isFunction(value.then)) return value;

如果不是,那么该值将被返回一个新创建的promise。该承诺会尽快解决,但不会在此事件循环迭代中解决。

return {
  then: function(callback) {
    var result = defer();
    nextTick(function() {
      result.resolve(callback(value));
    });
    return result.promise;
  }
};

这意味着您可以安全地从同步方法返回非承诺值。

function asyncFirst() {
    var def = $q.defer();

    $timeout(function(){
      $scope.first = true;
      def.resolve();
    }, 1000);

    return def.promise;
}

function syncSecond() {
     $scope.second = true;
    return {
        data1: 'abc',
        data2: 123
    };
}

$q.all([
    asyncFirst(),
    syncSecond()
])
.then(function(){
    $scope.all = true;
});

this jsbin example

中查看此操作

编辑:   正如用户@Bergi建议的那样,$q.when source可以根据需要将任何常规值转换为承诺但是,$q.when使用ref函数将值转换为承诺并结算在下一个事件循环迭代中的承诺。严格地说,方法本身是同步的,因为它返回没有延迟。但结果立即包含在承诺中,直到下一个事件循环迭代才会被使用。这意味着同步方法不会这样使用。至少在大多数人不会想象同步方法。 $q.all的总体结果将使用async这样的同步方法,但在下一次迭代中解决。考虑一下这个警告。

答案 2 :(得分:0)

如果你需要做更多的逻辑而不仅仅是返回值,并且你为很多同步函数做了一些事情,你可能想要创建一个为你做延迟逻辑的包装函数:

var makeAsync = function(fn){
 return function(){
   var deferred = $q.defer();       
   deferred.resolve(fn.apply(this,arguments));
   return deferred.promise;
  };
}

然后你可以这样做:

$q.all([
    asyncMethod1(),
    makeAsync(syncMethod1)()
])
.then(function (results) {