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

如何在持续添加Promise时,待所有Promise settled后关闭加载遮罩

PromiseBroker加载遮罩提前关闭的解决方案

问题场景

我写了一个PromiseBroker类用来管理API请求的Promise,目的是所有请求完成后关闭加载遮罩,但目前遇到遮罩提前关闭的问题:

  1. 添加Promise A - 显示加载遮罩
  2. Promise A 决议 - 关闭加载遮罩
  3. 添加Promise B - 显示加载遮罩
  4. 添加Promise C
  5. Promise B 决议 - 关闭加载遮罩
  6. Promise C 决议 - 这才是预期的遮罩关闭时机

我希望所有Promise(包括调用allSettled后新增的)都完成时才关闭遮罩,推测是因为等待期间Promise集合变化,旧的allSettled任务依然会触发关闭逻辑,想知道如何取消/覆盖旧的allSettled调用,只保留最新的。

原代码

class PromiseBroker {
    #promises = {};
    #overlayEle = document.getElementById('loading-overlay');
    constructor(){

    }
    get promises(){
        return this.#promises;
    }
    setPromise(key, value){
        this.promises[key] = value;
        this.#overlayEle.classList.remove('d-none');
        Promise.allSettled(Object.values(this.promises)).then(results => {
            this.#overlayEle.classList.add('d-none')
        });
    }
}

问题分析

每次调用setPromise都会创建一个新的Promise.allSettled实例,这些实例独立运行。比如添加Promise B后,会基于当时的[Promise B]集合启动一个allSettled任务,后续添加Promise C时又会基于[Promise B, Promise C]启动新任务。当Promise B完成时,第一个任务就会触发关闭遮罩,而此时Promise C还在运行,这就导致了提前关闭的问题。

解决方案

我们可以通过一个任务标识跟踪最新的allSettled任务,让只有最新任务的回调才执行遮罩关闭操作,旧任务的回调直接忽略。具体实现如下:

class PromiseBroker {
    #promises = {};
    #overlayEle = document.getElementById('loading-overlay');
    #currentTaskId = 0; // 跟踪最新任务的标识

    constructor(){

    }
    get promises(){
        return this.#promises;
    }
    setPromise(key, value){
        this.promises[key] = value;
        this.#overlayEle.classList.remove('d-none');
        
        // 生成新的任务ID,标记当前任务为最新
        const taskId = ++this.#currentTaskId;
        
        Promise.allSettled(Object.values(this.promises)).then(() => {
            // 仅当当前任务是最新的才执行关闭操作
            if (taskId === this.#currentTaskId) {
                this.#overlayEle.classList.add('d-none');
            }
        });
    }
}

关键逻辑说明

  • 新增#currentTaskId变量,每次调用setPromise时递增它,生成唯一的任务标识
  • 在allSettled的回调中,先判断当前任务的ID是否等于最新的#currentTaskId:
    • 如果相等,说明这是最后一次添加Promise后启动的任务,此时所有Promise都已完成,执行关闭遮罩
    • 如果不等,说明已经有新的Promise被添加,当前任务是旧任务,直接忽略回调

这样就能保证只有当所有已添加的Promise都完成,且没有后续新Promise添加时,才会关闭遮罩。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:20:04