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

使用JavaScript Proxy监听资源加载状态时遇set代理错误求助

问题描述

我想添加一种类似EventListener的机制,在所有应用资源加载完成时触发。我觉得Proxy是监控对象属性变化的合适方式,以下代码在jsfiddle能正常运行,但在实际加载资源的代码里使用时,出现错误:caught (in promise) TypeError: 'set' on proxy: trap returned falsish for property。我刚接触JavaScript Proxy,希望得到指导。

const log = console.log.bind(console);

let gameState = {
  live: false,
  loading: {
    images: false,
    sounds: false,
    controls: false,
  },
};

const loadingListener = {
  set(obj, prop, value) {
    Reflect.set(...arguments);
        if (gameState.loading.images &&
        gameState.loading.sounds &&
        gameState.loading.controls) {
      log(true);
    } else {
      log(false);
    }
  },
};

// Create the proxy object with the original object and the handler
const proxyObject = new Proxy(gameState.loading, loadingListener);

// Test the proxy object
proxyObject.images = true;
proxyObject.sounds = true;
proxyObject.controls = true;
解决方案

这个错误的核心原因是Proxy的set陷阱函数没有返回布尔值。根据ES规范,set陷阱必须返回true表示属性设置成功;返回false或未返回值(默认返回undefined,属于falsish值)时,严格模式环境会直接抛出TypeError。你的实际代码大概率运行在严格模式下(比如ES模块、打包后的项目代码),而jsfiddle默认环境是非严格模式,所以没触发这个错误。

修正步骤

在set函数末尾返回操作结果即可,最简单的方式是直接返回Reflect.set的执行结果(它本身会返回布尔值表示操作是否成功):

const log = console.log.bind(console);

let gameState = {
  live: false,
  loading: {
    images: false,
    sounds: false,
    controls: false,
  },
};

const loadingListener = {
  set(obj, prop, value) {
    // 执行属性设置并获取结果
    const setSuccess = Reflect.set(obj, prop, value);
    
    // 检查所有资源是否加载完成
    if (obj.images && obj.sounds && obj.controls) {
      log("所有资源加载完成!");
    } else {
      log("资源加载中...");
    }
    
    // 返回操作结果,避免报错
    return setSuccess;
  },
};

const proxyObject = new Proxy(gameState.loading, loadingListener);

// 测试
proxyObject.images = true;
proxyObject.sounds = true;
proxyObject.controls = true;

额外优化建议

  • 避免依赖外部的gameState,直接通过代理对象obj访问属性,降低代码耦合度:
    // 原代码依赖外部gameState
    // if (gameState.loading.images && ...)
    // 改为直接用obj
    if (obj.images && obj.sounds && obj.controls) { ... }
    
  • 实现真正的EventListener机制:可以在资源加载完成时触发自定义事件,让外部代码监听:
    // 定义自定义事件
    const resourcesLoadedEvent = new CustomEvent('resourcesLoaded');
    
    const loadingListener = {
      set(obj, prop, value) {
        const setSuccess = Reflect.set(obj, prop, value);
        if (obj.images && obj.sounds && obj.controls) {
          // 触发事件
          window.dispatchEvent(resourcesLoadedEvent);
        }
        return setSuccess;
      },
    };
    
    // 外部监听事件
    window.addEventListener('resourcesLoaded', () => {
      console.log("所有资源加载完成,开始初始化游戏!");
      // 这里写加载完成后的逻辑
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:53:00