什么是在循环中使用q promise的最佳方法?在迭代到下一个之前等待链完成

时间:2016-02-22 00:27:51

标签: javascript node.js promise q

我有以下情况:

var ids = [120, 121, 122, 123, 124]

function dummyPromise(pause) {
  var deferred = Q.defer();

  setTimeout(function() {
    console.log(pause);
    deferred.resolve(pause);
  }, pause);

  return deferred.promise;
}


for(var i = 0; i < ids.length; i++) {
  dummyPromise(ids[i])
    .then(dummyPromise)
    .then(dummyPromise)
    .then(dummyPromise)
    .then(dummyPromise)
    .done(function(){
      console.log('done')
    })
}

我想在迭代到下一个之前等待链完成。什么是解决这个问题的最好方法?

3 个答案:

答案 0 :(得分:1)

在这些示例中,我使用标准Promise。如果您需要使用(令人敬畏的)Q库,可以通过在Q.fcall(fn, arg)的地方替换Promise.resolve(arg).then(fn)或使用Q()代替Promise.resolve()来缩短Q库。

通过链接承诺

var q = Promise.resolve();

for (var i = 0; i < 10; i++) {
  (function(item, index){
    q = q.then(function() {
      return // do async stuff here
    });
  })(ids[i], i);
}

q.then(function() {
  // all iterations finished
});

使用数组

function forEachAsync(arr, fn) {
  var index = 0;
  function next() {
    if (index < arr.length) {
      var current = index++;
      return Promise.resolve().then(function() {
        return fn(arr[current], current, arr);
      }).then(next);
    }
  }
  return Promise.resolve().then(next);
}

...

forEachAsync(ids, function(item, idx) { ... }).then(...)

使用iterables

function forOfAsync(iterable, fn) {
  var iterator = iterable[Symbol.iterator]();
  function next() {
    var iteration = iterator.next();
    if (iteration.done) {
      return iteration.value;
    } else {
      return Promise.resolve(iteration.value).then(fn).then(next);
    }
  }
  return Promise.resolve().then(next);
}

forOfAsync(ids, function(id) { ... }).then(...)

使用async-await

for (let id of ids) {
  await doSomeAsyncStuffWithId(id);
}

答案 1 :(得分:0)

使用array#reduce - 您的代码看起来像

ids.reduce(function(prev, id) {
    return prev
    .then(function() {
        return dummyPromise(id)
    })
    .then(dummyPromise)
    .then(dummyPromise)
    .then(dummyPromise)
    .then(dummyPromise)
    .then(function(){ // if you do done you can't chain
      console.log('done')
    });
}, Q(null))
.done(function() { // done here though
    console.log('all done');
});

答案 2 :(得分:0)

感谢https://github.com/jprichardson/node-batchflow。我最后使用了这种方法:请参阅小提琴:https://jsfiddle.net/c9fxqhs5/

  var ids = [120, 121, 122, 123, 124]

  function dummyPromise(pause) {
    var deferred = Q.defer();

    setTimeout(function() {
      console.log(pause);
      deferred.resolve(pause);
    }, pause);

    return deferred.promise;
  }

  function again(i) {
    if (i < ids.length) {
      $('body').append('<p>processing: ' + i + '</p>');
      dummyPromise(ids[i])
        .then(dummyPromise)
        .then(dummyPromise)
        .then(dummyPromise)
        .then(dummyPromise)
        .done(function(result){
          $('body').append('<p>done: ' + i + ' result=' + result + '</p>');
          again(i+1)
        })
    } else {
      console.log('All Done.')
    }
  }

  again(0)