You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Promise.allSettled未等待Promise完成,如何解决?

问题

我有一个通过AJAX向服务器发送各类更新的函数,需要在所有更新发送完成后通知用户。我创建了Promise数组并使用Promise.allSettled,但该方法在多数Promise仍处于pending状态时就继续执行。

代码中通过IndexedDB打开pending-updates数据库,读取item-updates对象存储中的记录,将postItemUpdates返回的Promise加入promises数组。但控制台显示“all updates sent”日志早于“Sending 2 Item Updates To Server”,使用await delay(500)可临时解决但并非理想方案。控制台中then函数的values为空,成功消息直接触发,请问为何then函数会在Promise完成前触发?

相关代码片段

$('#updateModal').modal('show');
console.log('Sending Updates To Server');
let DBOpenRequest = window.indexedDB.open('pending-updates');
var promises=[];
var recordsToDelete=[];
DBOpenRequest.onsuccess = function(event)
{
  var db = event.target.result;
  // db transaction
   var itemUpdatePromises = [];
   itemUpdatesTransaction = db.transaction('item-updates', 'readwrite'),
   // get object store
   itemUpdates = itemUpdatesTransaction.objectStore('item-updates'),
   // get all records in object store
   itemUpdatesRecords = itemUpdates.getAll();
   itemUpdatesRecords.onsuccess = () =>
   {
     if (typeof itemUpdatesRecords.result!=='undefined')
     {
       if (itemUpdatesRecords.result.length>0)
       {
         recordsToDelete['itemUpdates']=itemUpdatesRecords.result;
         console.log('Sending '+itemUpdatesRecords.result.length+' Item Updates To Server');
          addElement('logWindow', '<p>Sending '+itemUpdatesRecords.result.length+' Item Updates To Server  <i id="itemUpdateIcon" class="fa-duotone fa-paper-plane"></i></p>')
         $.each(itemUpdatesRecords.result, function( index, value )
         {
           var promise = postItemUpdates(value);
           promises.push(promise);
         });
       }
     }
   };
   itemUpdatesRecords.onerror = () =>
   {
    //db.close;
    console.log('Item Updates Object Store Not Found', itemUpdatesRecords.error);
   };
await delay(500); // this allowed the time for the promises array to populate before continuing - not an ideal solution but solved my issue.
console.log("before", promises.join(","))
Promise.allSettled(promises).then(function (values)
{
  console.log("after", values.join(","));
 const rejected = values.filter(result => result.status === 'rejected').map(result => result.reason);
 if ((Array.isArray(rejected) && rejected.length > 0) || typeof rejected === 'undefined')
 {
   errorMsg('There Was A Problem Sending Updates To Server');
 }
console.log('all updates sent')

解答

核心问题是IndexedDB的操作是异步回调模式,你执行Promise.allSettled时,IndexedDB还没完成数据读取,promises数组还是空的。

具体原因

  1. DBOpenRequest.onsuccess和itemUpdatesRecords.onsuccess都是异步回调,这些回调会在当前同步代码全部执行完之后才触发。
  2. 你写的await delay(500)之后的代码(包括Promise.allSettled)会先于IndexedDB的回调执行,此时promises数组还没被填充,Promise.allSettled([])会立即resolve,直接进入then函数打印“all updates sent”。
  3. 之后IndexedDB的回调才触发,往promises数组里加Promise,但此时Promise.allSettled已经执行完毕,根本不会等待这些新加的Promise。

正确解决方法

把整个IndexedDB的操作包装成Promise,确保在数据读取完成、promises数组填充完毕后,再执行Promise.allSettled。

修改后的代码示例:

$('#updateModal').modal('show');
console.log('Sending Updates To Server');

// 将IndexedDB操作封装为Promise
const getPendingUpdates = () => {
  return new Promise((resolve, reject) => {
    const DBOpenRequest = window.indexedDB.open('pending-updates');
    const promises = [];
    const recordsToDelete = [];

    DBOpenRequest.onsuccess = (event) => {
      const db = event.target.result;
      const itemUpdatesTransaction = db.transaction('item-updates', 'readwrite');
      const itemUpdates = itemUpdatesTransaction.objectStore('item-updates');
      const itemUpdatesRecords = itemUpdates.getAll();

      itemUpdatesRecords.onsuccess = () => {
        if (itemUpdatesRecords.result?.length > 0) {
          recordsToDelete['itemUpdates'] = itemUpdatesRecords.result;
          console.log(`Sending ${itemUpdatesRecords.result.length} Item Updates To Server`);
          addElement('logWindow', `<p>Sending ${itemUpdatesRecords.result.length} Item Updates To Server  <i id="itemUpdateIcon" class="fa-duotone fa-paper-plane"></i></p>`);
          
          // 填充Promise数组
          itemUpdatesRecords.result.forEach(value => {
            promises.push(postItemUpdates(value));
          });
        }
        // 数据读取完成,返回Promise数组和待删除记录
        resolve({ promises, recordsToDelete });
      };

      itemUpdatesRecords.onerror = () => {
        console.log('Item Updates Object Store Not Found', itemUpdatesRecords.error);
        reject(itemUpdatesRecords.error);
      };
    };

    DBOpenRequest.onerror = () => {
      reject(DBOpenRequest.error);
    };
  });
};

// 按顺序执行异步流程
(async () => {
  try {
    const { promises } = await getPendingUpdates();
    console.log("before", promises.join(","));
    const values = await Promise.allSettled(promises);
    console.log("after", values.join(","));
    
    const rejected = values.filter(result => result.status === 'rejected').map(result => result.reason);
    if (rejected.length > 0) {
      errorMsg('There Was A Problem Sending Updates To Server');
    }
    console.log('all updates sent');
  } catch (err) {
    console.error('Failed to load pending updates:', err);
    errorMsg('There Was A Problem Loading Pending Updates');
  }
})();

关键改动点

  • 将IndexedDB的异步回调操作全部包裹在一个Promise中,只有当数据读取完成、promises数组填充好后才resolve。
  • 使用async/await等待IndexedDB操作完成,再执行Promise.allSettled,确保数组已经有内容。
  • 移除了不可靠的delay(500),完全基于异步操作的实际完成时机控制流程。

内容的提问来源于stack exchange,提问作者AKAust

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:15:36