javascript 使用$q串行执行多个任务

gfttwv5a  于 2022-12-02  发布在  Java
关注(0)|答案(3)|浏览(143)

现在我在玩超级英雄AngularJS的$q,我有三个asynchronous任务,分别叫taskAtaskBtaskC,我想一个一个的执行,现在我用的是$qall()方法,我在做以下的事情:

var taskA = function() {
    var d = $q.defer();
    $timeout(function() {
      $log.log('Task A');
      d.resolve('A is done');
    }, Math.random() * 5000);
    return d.promise;
  };

  var taskB = function() {
    var d = $q.defer();
    $timeout(function() {
      $log.log('Task B');
      // d.resolve('B is done');
      d.reject('B is rejected');
    }, Math.random() * 5000);
    return d.promise;
  };

  var taskC = function() {
    var d = $q.defer();
    $timeout(function() {
      $log.log('Task C');
      //d.resolve('C is done');
      d.reject('C is rejected');
    }, Math.random() * 5000);
    return d.promise;
  };

  $scope.startWithAll = function() {
    $log.log('With all started');
    var promises = [taskA(), taskB(), taskC()];
    $q.all(promises).then(
      //success callback...
      function(result) {
        $log.log(result);
      },
      //error callback
      function(error) {
        $log.log(error);
      },
      //progress callback
      function() {
        //todo implement it
      }
    ).finally(function() {
      $log.log('I am from finally');
    });
  };

这种方法的问题是我的所有任务都是并行执行的。在thensuccess中,我在array中得到每个任务的结果。如果任何一个任务被拒绝,那么其余的任务继续执行,但执行错误callback,我在回调中得到错误object。我想做的是首先只执行taskA,然后是taskB,再然后是taskC,如果其中任何一个被拒绝或失败,那么其余的任务都不应该执行。而且执行不应该是并行的,而应该是串行的。为了串行地执行它们,我这样做:

$scope.startSerial = function() {
    $log.log('Serially started');
    $q.when().then(function(result) {
      $log.log(result);
      return taskA();
    }).then(function(result) {
      $log.log(result);
      return taskB();
    }).then(function(result) {
      $log.log(result);
      return taskC();
    }).finally(function() {
      $log.log('I am from finally');
    });
  };

这就解决了我的问题,但问题是在第一个callback中我得到的是undefined,我对此没有任何问题,所以我们可以省略这一部分。但目前我只有三个任务,所以这种方法是好的,但如果明天我有超过三个任务,那么这将是一个很好的实施方式。有没有其他的方法可以这样做,因为我不能一直在另一个下面添加多个then。我已经创建了plunkr for this。我正在考虑创建一个service,它将创建这个任务执行层次结构,但我不知道如何做到这一点。

bihw5rsg

bihw5rsg1#

你可以创建一个循环,连接所有的承诺:

function each(arr, func) {
    for (var i = 0; i < arr.length; i++) {
      func(arr[i], i);
    }
  }

  $scope.startSerial = function() {
      var funcs = [taskA, taskB, taskC];
      $log.log('Serially started');
      var s = $q.when();
      each(funcs, function (func) {
          s = s.then(function (result) {
            $log.log(result);
            return func();
          });
      });
      s.finally(function () {
        $log.log('I am from finally');
      });
  }

这应该会产生与原始脚本相同的行为,但是您可以简单地调整数组funcs,而不是为每个promise添加额外的代码块。

lokaqttq

lokaqttq2#

你可以把任务按照你希望它们执行的顺序放在一个数组中,然后循环遍历它们,如果一个任务失败了就退出循环。

rt4zxlrg

rt4zxlrg3#

我知道这很老了,但是我最近还是不得不处理这个问题,我最初使用的是一个循环,然后我决定创建一个递归方法,在其中传递promise数组和当前索引promise。

//However you populate your array
let myPromises = [];

//Start with the first promise, which is a zero index
recursiveFunction(myPromises, 0)
    .finally(function() {
        console.log("all promises done");
    });

function recursiveFunction(promises, promiseIndex) {
    //Make sure your promise index is valid
    if (promiseIndex < 0 || promiseIndex >= promises.length) {
        return $q.reject("invalid index");
    }

    let defer = $q.defer();

    promises[promiseIndex]()
        .finally(function() {
            if (promiseIndex < promises.length - 1) {
                recursiveFunction(promises, ++promiseIndex)
                    .finally(function () {
                        defer.resolve();
                    });
            } else {
                defer.resolve();
            }        
        });

    return defer.promise;
}

相关问题