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

基于Proxy实现可更新Promise的技术问询与问题验证

可更新Promise实现相关问题

编辑说明

已更新本问题,旧问题已迁移。可通过代码片段查看POC。

目标

实现或模拟可更新、生命周期可重置的Promise,同时通过控制反转实现对Promise决议的更强控制,示例代码如下:

const ex = {};  
const prom = new Promise<T>((resolve, reject) => {
    ex.resolve = resolve;
    ex.reject = reject;
});

实现方案

代码片段支持输入新值并选择决议状态(resolve/reject),被拒绝的值将高亮显示。默认情况下,Promise以值default被拒绝。

编辑补充:默认已绑定.then()回调(代码第85行),首次决议后值会被打印两次,此为预期行为。

核心代码

JavaScript实现

class UpdatablePromise {
  /**
   * @param prom - 初始Promise对象
   * @param executor - 可选参数,用于将执行器存储到内部
   * @returns UpdatablePromise实例
   */
  constructor(prom, executor) {
    this.value = undefined;
    this.executors = [];
    if (executor) this.executors.push(Object.assign({}, executor));
    
    /**
     * 调用之前存储的resolve/reject函数,完成旧Promise的决议
     * 辅助函数,减少update方法中的代码重复
     */
    const prevResolvers = (type) => {
      return (val) => {
        const flag = type === "reject";
        while (true) {
          const executor = this.executors.shift();
          if (executor) flag ? executor.reject(val) : executor.resolve(val);
          else break;
        }
        return val;
      };
    };
    
    const handler = {
      get: (target, prop) => {
        if (prop === "update") {
          // 返回更新方法,接收新Promise和可选执行器
          return (v, executor) => {
            this.value = v;
            if (executor) this.executors.push(executor);
            // 绑定新Promise的回调,在其决议时完成所有旧Promise的决议
            v.then(
              (val) => prevResolvers("resolve")(val),
              (val) => prevResolvers("reject")(val)
            );
          };
        } else if (typeof this.value === "undefined") {
          // 若未更新过,返回初始Promise的属性/方法
          return typeof target[prop] === "function" ?
            target[prop].bind(target) :
            target[prop];
        } else if (prop === "then") {
          // 转发then方法到当前最新的Promise
          return (onfulfilled, onrejected) =>
            this.value.then(onfulfilled, onrejected);
        } else if (prop === "catch") {
          return (onrejected) => this.value.catch(onrejected);
        } else if (prop === "finally") {
          return (onfinally) => this.value.finally(onfinally);
        } else {
          return target[prop];
        }
      },
    };
    return new Proxy(prom, handler);
  }
}

配套HTML页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>
<body>
  <label for="input">输入更新Promise的值:</label>
  <input id="input" />
  <div>
    <button id="res">resolve</button>
    <button id="rej">reject</button>
  </div>
  <pre id="output"></pre>
</body>
</html>

此外还有TypeScript版本(可能未同步更新,优先参考上述JS代码)。

问题背景

该实现在控制台或在线编辑器中可正常运行,最初误以为在Workbox的Service Worker中仅返回旧值,后排查发现是其他函数反复将Promise更新至数据库值导致,实际在Service Worker中可用。

核心问询

  1. 该实现是否真如预期工作?即除可重置生命周期外,完全兼容Promise特性,更新后所有待处理的await或回调均使用新值决议。
  2. 若实现有效,能否添加state成员变量以同步追踪Promise状态?

解答

1. 实现的有效性与兼容性

该实现基本符合预期,但有几个细节需要注意:

  • 待处理回调/await的触发:调用update传入新Promise后,新Promise决议时会遍历执行所有存储的旧executor的resolve/reject,能让所有之前挂起的await或.then()回调拿到新值,符合设计目标。
  • Promise兼容性:通过代理拦截then/catch/finally并转发到最新Promise,保证了大部分原生Promise特性的兼容。但存在小局限:
    • 原生Promise的内部属性(如Symbol.toStringTag)未被代理,若业务代码依赖这些属性可能出现问题;
    • 多次调用update时,若前一个Promise未决议,新Promise决议会覆盖等待队列,这符合“重置生命周期”的设计,但需确认业务场景是否接受;
    • 已决议的Promise回调不会重复触发,符合原生Promise特性。

整体来看,在常规业务场景下,该实现能满足“可更新、兼容Promise特性”的需求。

2. 添加state成员变量追踪状态

可以添加state变量同步追踪当前Promise的状态,实现思路如下:

  1. 在类初始化时添加状态变量:
    constructor(prom, executor) {
      this.value = undefined;
      this.executors = [];
      this.state = 'pending'; // 初始状态为pending
      // ... 其他原有代码
    }
    
  2. 在update方法中重置状态,并监听新Promise的决议更新状态:
    return (v, executor) => {
      this.value = v;
      this.state = 'pending'; // 新Promise初始为pending
      if (executor) this.executors.push(executor);
      v.then(
        (val) => {
          this.state = 'fulfilled';
          return prevResolvers("resolve")(val);
        },
        (val) => {
          this.state = 'rejected';
          return prevResolvers("reject")(val);
        }
      );
    };
    
  3. 在代理的get方法中,当访问state时返回当前值:
    const handler = {
      get: (target, prop) => {
        if (prop === 'state') {
          return this.state;
        }
        // ... 其他原有逻辑
      }
    };
    

通过上述修改,就能实时同步追踪当前活跃Promise的状态(pending/fulfilled/rejected)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:31:59