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);
});
试图理解 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 中包含 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);
});