使用 $q 串行执行许多任务

Serial Execution of many task with $q

现在玩的是超级英雄$qAngularJS。我有三个 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 来创建这个任务执行层次结构,但我不知道该怎么做。

您可以按照您希望它们执行的顺序将任务放入一个数组中,然后循环遍历它们并在任务失败时退出循环。它不是很性感,但它可以完成工作。

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

  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 而不是为每个承诺添加额外的代码块。