簡體   English   中英

如何在while循環中串聯諾言

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM