3

我的应用程序有许多同步和异步(执行 $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.promise?只是试图使同步方法尽可能简单。

4

3 回答 3

1

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

return {
    data1: 99,
    data2: 123
};

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


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

您可以使用$q.when

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

如果该值还不是一个promise,那么将返回一个promise,该promise 将尽快用该值解决。请注意,这必然会在您的代码中引入异步,因此它不再是真正的syncMethod

于 2014-05-21T11:09:56.537 回答
1

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

长答案

如果我们查看角度代码,$q.all我们会在这一行看到输入参数是如何处理的:

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

所以每个参数都被传递给在这一行定义ref的函数。接受一个参数,如果它是一个承诺,它会返回它ref

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

如果不是,则该值将用一个新创建的承诺包装,该承诺将被返回。该承诺会尽快得到解决,但不会在此事件循环迭代中解决。

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

这个 jsbin 示例中查看它的实际效果

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

于 2014-05-21T11:27:53.663 回答
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) {
于 2014-05-21T11:20:15.940 回答