Promise.all 遍历生成器无效

Promise.all not valid to iterate through generators

试图理解 Javascript 生成器和承诺,我检查过它们是很好的盟友。我需要遍历承诺的协程(Promise.coroutine 来自 Bluebird 库)使得以正确的顺序执行一些承诺变得容易。使用此代码(对延迟的反模式感到抱歉,我稍后会学会避免它):

function myPromise(x,time,i){
    var deferred = Q.defer();

    setTimeout(() => {
        deferred.resolve(x + i);
    },time);

    return deferred.promise;
}

router.get('/', function(req, res, next) {
    for (var i = 0; i < 5; i++) {      
        Promise.coroutine(function*(i) {
            var a = yield myPromise('a',6000,i);
            var b = yield myPromise('b',1000,i);
            console.log(a,b);
        })(i)
        .then(() => {
            console.log('Then');
        }).
        catch((err) => next(err));
    }
});

控制台中的输出(几乎)正确:

a0 b0
a1 b1
a2 b2
Then
Then
Then
a3 b3
a4 b4
Then
Then

检查一下,我的 for 循环似乎不太好,因为 Then.

有些 promise 在其他 promise 之前结束

如果我在 promise 中包含 if(i == 3) deferred.reject(new Error(' ERROR!!'));,则仅针对该 promise 而不是其他 promise 抛出错误,并且它在其他 promise 之后抛出:

ERROR!!
a0 b0
Then
a1 b1
a2 b2
Then
Then
a4 b4
Then

我认为使用 for 循环进行迭代永远不是解决此类问题的方法。再研究一点,我尝试将 Promise.all 与对 Promise.coroutine:

的一系列调用一起使用
    Promise
        .all([
            Promise.coroutine(1),
            Promise.coroutine(2),
            Promise.coroutine(3)
        ])
        .then(() => {
            console.log('then');
        })
        .catch((err) => next(err));

但在这种情况下,我的错误是:

generatorFunction must be a function

如果我这样做:

var coroutine = function* coroutine(i) {
    var a = yield myPromise('a',6000,i);
    var b = yield myPromise('b',1000,i);
    console.log(a,b);
};

相同的 generatorFunction 必须是一个函数 仍然存在。

你知道这里有什么问题吗,或者是否有比 Promise.all 更好的 "iterate" 方法?

sorry for the deferred anti-pattern

实际上你没有在 myPromise 中使用 the deferred antipattern,使用 deferreds 从像 setTimeout 这样的回调异步函数中获得承诺是完全没问题的。您 可以 改用 Promise 构造函数,但这不是绝对必要的。最好的解决方案当然是 Promise.delay (Bluebird) 或 Q.delay (Q) :-)

my for loop seems to be not good because some promises are ending before the others

那是因为您对协程(执行异步操作)的调用在循环内。如果您改为将循环放在生成器函数中,它将按预期工作:

router.get('/', function(req, res, next) {
    Promise.coroutine(function*() {
        for (var i = 0; i < 5; i++) {      
            var a = yield myPromise('a',6000,i);
            var b = yield myPromise('b',1000,i);
            console.log(a,b);
            console.log('Then');
        }
    })()
    .catch((err) => next(err));
});

甚至更好:

var run = Promise.coroutine(function*(req, res, next) {
    for (var i = 0; i < 5; i++) {      
        var a = yield myPromise('a',6000,i);
        var b = yield myPromise('b',1000,i);
        console.log(a,b);
        console.log('Then');
    }
});
router.get('/', function(req, res, next) {
    run(req, res, next).catch(next);
});