[英]How to chain promises in series in a while loop
我必須對多個數據庫進行查詢。 基本上,一組承諾必須按順序完成。 我在一個while循環中實現它。 數據庫是根據日期命名的。 我還必須將請求延遲設置為400ms乘以每個諾言之間傳遞的循環量(400 * count)。 如果有幫助,我將cloudant用作數據庫,類似於mongodb / couchdb,但具有在線實例。
因此,我實現了一個查詢函數,該函數將采用開始和結束日期,並將檢索范圍內的所有值。 如果日期相同,則將查詢一個數據庫,否則將查詢日期范圍之間每天的多個數據庫。 我主要在if語句中的else塊遇到麻煩,如下所示。
db.predQuery = (start, end, locationCode) => {
return new Promise((resolve, reject) => {
let data = [];
const startDate = moment(start, "MM/DD/YYYY");
const endDate = moment(end, "MM/DD/YYYY");
if (startDate.diff(endDate) === 0) {
// THIS IF BLOCK WORKS GOOD
let dbName = `prediction_${String(locationCode)}_`;
dbName += startDate.format("YYYY-MM-DD");
const db = this.cloudant.use(dbName);
return db.find({selector: {_id: {'$gt': 0}}}).then((body) => {
data = body.docs;
return resolve(data);
});
} else {
// THIS BLOCK IS WHERE THE PROBLEM IS
// This is to start off the promise chain in the while loop
let chainProm = Promise.resolve(1);
let iterator = moment(startDate);
let count = 0;
// While loop for the series of promises
while (iterator.isBefore(endDate) || iterator.isSame(endDate)) {
//dbName Format: prediction_0_2019-05-28
let dbName = `prediction_${String(locationCode)}_`;
dbName += iterator.format("YYYY-MM-DD");
const db = this.cloudant.use(dbName);
count += 1;
// Set off chain of promises
chainProm = chainProm.then(() => {
setTimeout(()=>{
db.find({selector: {_id: {'$gt': 0}}}).then((body) => {
// Keep adding on to the old array
data = data.concat(body.docs);
});
},count*400);
});
// Move to the next day
iterator.add(1,'days');
}
// Once all done resolve with the array of all the documents
return resolve (data);
}
})
};
基本上,假設輸出是日期范圍之間所有文檔的數組。 現在,單個日期有效,但是當我執行一系列日期操作時,請求沒有通過,或者我達到了極限,或者說承諾從未解決。 我認為這可能不是解決此問題的最佳方法,並且可以接受任何解決方案。 任何幫助是極大的贊賞。
您的chainProm
沒有與predQuery
的外部調用連接- resolve
將立即被調用。
您可能會發現使用async
/ await
容易得多,而delay-inside-loop邏輯將更容易理解:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
db.predQuery = async (start, end, locationCode) => {
const startDate = moment(start, "MM/DD/YYYY");
const endDate = moment(end, "MM/DD/YYYY");
if (startDate.diff(endDate) === 0) {
// THIS IF BLOCK WORKS GOOD
let dbName = `prediction_${String(locationCode)}_`;
dbName += startDate.format("YYYY-MM-DD");
const db = this.cloudant.use(dbName);
const body = await db.find({selector: {_id: {'$gt': 0}}});
return body.docs;
}
const iterator = moment(startDate);
const data = [];
const testShouldIterate = () => iterator.isBefore(endDate) || iterator.isSame(endDate);
let shouldIterate = testShouldIterate();
while (shouldIterate) {
//dbName Format: prediction_0_2019-05-28
let dbName = `prediction_${String(locationCode)}_`;
dbName += iterator.format("YYYY-MM-DD");
const db = this.cloudant.use(dbName);
const body = await db.find({selector: {_id: {'$gt': 0}}});
data.push(body.docs);
// Move to the next day
iterator.add(1,'days');
shouldIterate = testShouldIterate();
// Don't delay on the final iteration:
if (!shouldIterate) {
break;
}
await delay(400);
}
// Once all done resolve with the array of all the documents
return data;
};
使用此實現,任何錯誤都將被發送到predQuery
的調用者(錯誤將導致它返回的Promise被拒絕),因此,在調用predQuery
,請確保predQuery
放置catch
。
我還沒有完全理解您的代碼。 但是,如果查詢彼此獨立,則Promise.all()
似乎可以解決您的問題:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
如果實際上您需要按同步順序運行諾言,請嘗試僅等待循環中的諾言解析。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.