AngularJS:链接forEach循环的承诺

Jon*_*lis 7 javascript promise angularjs angular-promise

我无法绕开承诺.我正在使用Google Earth API对地址进行"浏览".游览只是一个持续大约一分钟的动画,当一个完成时,下一个应该开始.

这是我的游览功能:

var tourAddress = function (address) {
        return tourService.getLatLong(address).then(function (coords) {
            return tourService.getKmlForCoords(coords).then(function (kml) {
                _ge.getTourPlayer().setTour(kml);
                _ge.getTourPlayer().play();

                var counter = 0;
                var d = $q.defer();
                var waitForTour = function () {
                    if (counter < _ge.getTourPlayer().getDuration()) {
                        ++counter;
                        setTimeout(waitForTour, 1000);
                    } else {
                        d.resolve();
                    }
                };

                waitForTour();

                return d.promise;
            });
        });
    }
Run Code Online (Sandbox Code Playgroud)

这看起来效果很好.它启动动画并返回一个在动画完成时解析的promise.现在我有一个地址数组,我想做一个foreach他们:

$scope.addresses.forEach(function (item) {
      tourAddress(item.address).then(function(){
          $log.log(item.address + " complete");
       });
 });
Run Code Online (Sandbox Code Playgroud)

当我这样做时,它们都会同时执行(Google Earth会为最后一个地址执行动画)并且它们都会同时完成.如何在上一个完成之后将它们链接起来?

UPDATE

我用@ phtrivier的帮助来实现它:

 $scope.addresses.reduce(function (curr,next) {
      return curr.then(function(){
            return tourAddress(next.address)
      });
  }, Promise.resolve()).then(function(){
      $log.log('all complete');
  });
Run Code Online (Sandbox Code Playgroud)

pht*_*ier 6

你是对的,请求立即完成,因为调用tourAddress(item.address)执行请求在请求完成时返回已解析的Promise.

由于您在循环中调用tourAddress,因此会生成许多Promise,但它们并不相互依赖.

你想要的是调用tourAdress,获取返回的Promise,等待它被解析,然后再用另一个地址调用tourAddress,依此类推.

手动,你必须写下这样的东西:

tourAddress(addresses[0])
  .then(function () {
     return tourAddress(addresses[1]);
  })
  .then(function () {
     return tourAddress(addresses[2]);
  })
  ... etc...
Run Code Online (Sandbox Code Playgroud)

如果您想自动执行此操作(您不是第一个:如何按顺序执行承诺数组?),您可以尝试将地址列表减少为将执行整个链的单个Promise.

_.reduce(addresses, function (memo, address) {

   return memo.then(function (address) {
         // This returns a Promise
         return tourAddress(address);   
   });

}, Promise.resolve());
Run Code Online (Sandbox Code Playgroud)

(这是使用下划线和蓝鸟的伪代码,但它应该是可适应的)

  • 为什么`_.reduce`?您可以轻松地执行`addresses.reduce` (2认同)