2016-07-03 59 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