试图理解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.all
与Promise.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
?
答案 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);
});