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

Promise内window.onstorage仅触发一次:能否在Promise中监听事件?

问题解答

可以在Promise相关逻辑中监听storage事件,但你的写法存在两个核心问题,导致只能监听到一次事件:

当前写法的问题

  1. Promise的决议特性限制:Promise一旦执行resolve或reject,就会进入已完成/已拒绝的终态,后续再调用resolve不会有任何效果。你把resolve放在window.onstorage回调里,第一次触发storage事件时Promise就完成了,后续事件触发时回调里的resolve已经失效。
  2. 事件注册方式错误:使用window.onstorage = ...是直接覆盖事件处理函数,而非添加新的监听器。这种写法不仅容易覆盖其他地方的事件逻辑,而且结合Promise的特性,直接导致后续事件无法被捕获。

正确实现方式

如果需要持续监听storage变化,不能把事件回调和单个Promise的resolve绑定。应该把初始数据获取(用Promise)和持续事件监听分开处理,同时使用标准的事件注册方式addEventListener,并在组件卸载时清理监听器避免内存泄漏。

修改后的代码示例:

const connect = useCallback(() => {
  // 用Promise处理初始数据的异步获取
  return Promise.all([infuraStorageData, metamaskStorageData])
    .then(response => {
      const initialData = {
        infuraData: response[0],
        metamaskData: response[1]
      };

      // 返回初始数据,以及用于订阅storage变化的方法
      return {
        initialData,
        subscribe(onStorageChange) {
          const storageHandler = (e) => {
            // 这里可以根据事件e获取最新的storage数据,或者重新请求
            Promise.all([infuraStorageData, metamaskStorageData])
              .then(updatedResponse => {
                onStorageChange({
                  infuraData: updatedResponse[0],
                  metamaskData: updatedResponse[1]
                });
              });
          };

          window.addEventListener('storage', storageHandler);
          // 返回取消订阅的函数,用于组件卸载时清理
          return () => window.removeEventListener('storage', storageHandler);
        }
      };
    })
    .catch(error => Promise.reject(error));
}, [infuraStorageData, metamaskStorageData]);

useEffect(() => {
  let unsubscribe;
  useStorageDBHook.connect()
    .then(({ initialData, subscribe }) => {
      console.log('初始连接数据:', initialData);
      // 订阅storage变化,每次触发都会执行回调
      unsubscribe = subscribe((updatedData) => {
        console.log('storage更新:', updatedData);
      });
    })
    .catch(e => console.error('连接失败:', e));

  // 组件卸载时取消监听,避免内存泄漏
  return () => {
    if (unsubscribe) unsubscribe();
  };
}, [useStorageDBHook]);

关键改进点

  • 把初始数据获取和事件监听拆解开:Promise只负责完成初始的异步数据加载,事件监听通过独立的subscribe方法处理。
  • 使用addEventListener注册事件,支持多个监听器,且能通过removeEventListener清理。
  • 组件卸载时主动移除事件监听器,避免内存泄漏。
  • 每次storage事件触发时,重新获取最新数据并通过回调通知,保证响应所有变化。

内容的提问来源于stack exchange,提问作者THIAGO DE BONIS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:20:30