Promise.all无效迭代生成器

时间:2016-07-03 11:00:31

标签: javascript node.js promise generator bluebird

试图理解Javascript生成器和承诺,我已经检查过它们是很好的盟友。我需要遍历承诺的协程(来自Bluebird库的Promise.coroutine),以便以正确的顺序轻松执行某些承诺。使用此代码(对于延迟的反模式,我将学习以后避免它):

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而在其他承诺之前结束。

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

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

我认为迭代for循环并不是解决这类问题的方法。再研究一下,我尝试将Promise.allPromise.coroutine的一系列调用一起使用:

    Promise
        .all([
            Promise.coroutine(1),
            Promise.coroutine(2),
            Promise.coroutine(3)
        ])
        .then(() => {
            console.log('then');
        })
        .catch((err) => next(err));

但在这种情况下,我接受了错误:

  

generatorFunction必须是一个函数

如果我这样做:

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

1 个答案:

答案 0 :(得分:2)

  

抱歉延迟反模式

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

  

我的for循环似乎并不好,因为有些承诺在其他承诺之前结束

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

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);
});