2016-07-03 62 views
1

试图理解Javascript生成器和承诺,我已检查他们是好的ALAX。我需要迭代抛出承诺的协程(来自Bluebird libray的Promise.coroutine)可以很容易地按照正确的顺序执行一些承诺。有了这个代码(抱歉推迟反模式,我将学习以避免以后吧):Promise.all无效迭代抛出生成器

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而在别人之前结束。

如果我在承诺iinclude 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 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 must be a function仍然存在。

你知道这里有什么问题吗?或者如果有更好的方法来“迭代”比Promise.all

非常感谢。

回答

2

sorry for the deferred anti-pattern

其实你并没有myPromise使用the deferred antipattern,使用deferreds摆脱回调回吐异步功能的承诺像setTimeout是完全正常。你可能已经使用了Promise构造函数,但它并不是必须的。最好的解决办法是简单Promise.delay(蓝鸟)或课程的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); 
}); 
+1

它一般不提倡创造协同程序为获得每次迭代运行匿名函数。最好创建一次,然后将它们传入。 –

+0

@BenjaminGruenbaum:我想过包含它,但认为它不是必需的。现在添加:-) – Bergi