2017-06-16 75 views
0

我最近開始使用promise,因此,例如,我可以等到在執行下一個函數之前用x個記錄更新數據庫。我發現自己正在計算循環迭代,以便在正確的時間解決承諾。例如:如何避免計數JavaScript Promises中的循環迭代

var updateAccounts = function(accounts) { 
 
    var promise = new Promise(function(resolve, reject) { 
 
     var counter = 0; 
 
     accounts.forEach(function(account) { 
 

 
     db.collection('accounts').update({ 
 
      name: account.name 
 
     }, { 
 
      $set: { 
 
      balance: account.balance 
 
      } 
 
     }); 
 
     counter++ 
 
     if (counter == accounts.length) { 
 
      resolve('accounts updated'); 
 
     } 
 
     }); 
 
    } 
 
    }); 
 
    return promise; 
 
}

有沒有辦法等到循環沒有計算迭代完成了嗎?這只是一種黑客行爲,但我不確定它是否真的存在問題。

+0

您並未等待更新完成。循環是同步的,更新不是。當循環已經結束時,它們在並行中發生。查看[Promise.all()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) – Thomas

+0

這是mongodb嗎?貓鼬? – trincot

+0

@Thomas所以​​你的意思是promise.all,每個更新都是一個承諾? – chuckieDub

回答

4

根據MDN

無極對象表示異步操作的最終完成(或失敗),並且其結果值。

基本上這意味着Promise應跟蹤單個異步操作的結果。

但是,在您的示例中,您在一個Promise內執行了多個異步操作(即​​)。你不得不求助於一個互動計數來追蹤完整性,而不是依靠這樣做的承諾。

要解決此問題(雙關意圖:D),您的每個異步請求應該都有自己的Promise

由於您有多個更新並因此有多個承諾,所以您可以使用Promise.all來捕獲所有承諾成功完成時的情況。

這裏是你的代碼示例的快速適應:

var updateAccounts = function(accounts) { 
    var promises = []; 
    accounts.forEach(function(account) { 
     var promise = new Promise(function(resolve, reject) { 
      db.collection('accounts').update({ 
       name: account.name 
      }, { 
       $set: { 
       balance: account.balance 
       } 
      }); 
     }); 
     promises.push(promise); 
    }); 

    Promise.all(promises).then(function(arrPromises) { 
     console.log("All promises resolved."); 
    }).catch(function(failedPromise) { 
     console.log("Something failed."); 
    }); 

} 

從我的例子中唯一缺少的是​​後調用resolve成功執行。更新成功完成後,您必須調用resolve,或者如果更新失敗,則必須調用reject。這是告訴它已經完成的承諾。

我的代碼示例在沒有這個功能的情況下無法正常工作,但是從原始代碼示例中不清楚哪裏應該指定​​的回調 - 所以我省略了它。

0

你可以在foreach後試試嗎?

var updateAccounts = function(accounts) { 
 
    var promise = new Promise(function(resolve, reject) { 
 
     ... 
 
     accounts.forEach(function(account) { 
 
     ... 
 
     }); 
 
    <---Here<-- 
 
    } 
 
    }); 
 
    return promise; 
 
}
這似乎很奇怪要檢查內循環的foreach完成。也許你想確保帳戶數組有一些元素?您也可以在循環外檢查零或非零長度。

+0

我想我不明白異步BS同步,但基本上我想確保循環已完成,然後再移動到下一個函數。什麼是最好的方法來做到這一點? foreach是否默認這樣做? – chuckieDub

+0

我最終取消選擇其他答案並選擇這一個。你是對的,我可以在循環後解決。出於某種原因,我有一種經歷讓我覺得我必須計算循環,這是不正確的。謝謝你,你救了我很多時間! – chuckieDub

+1

這個答案是完全錯誤的。我強烈建議您重新閱讀下面的答案。 – Randall444