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

基于Node.js Events与ES6模块化实现自定义状态管理器的问题

嘿,我看你已经自己找到了解决的核心思路——把StateManager实例传递给Loader,不过咱们再理清楚之前出错的原因,以及优化后的代码细节:

你之前碰到的Cannot read property 'emit' of undefined错误,核心问题有两个:

  1. 静态方法拿不到实例属性:Manager里的loadedImages是静态方法,它属于类本身,根本访问不到实例的this.state对象,自然会报错。
  2. 图片加载的异步逻辑没处理对:原来的load方法里直接判断this.loadCount === this.imageCount,但图片加载是异步操作,这行代码会在所有图片开始加载前就执行,根本等不到加载完成的时机。

下面是完善后的代码,还有几个关键优化点:

修改后的Loader.js

'use strict';
import Manager from './Manager';

const DIRECTORY = 'assets/img/';
const IMG = {
  BACKGROUND_01: 'background_01.jpg',
  PLAYER_01: 'player_01.png',
  KEEPER_01: 'keeper_01.png'
}

export default class Loader {
  constructor() {
  }

  setup(state) {
    this.state = state;
    this.load();
  }

  load() {
    this.imageCount = Object.values(IMG).length; // 直接取图片总数,避免手动累加出错
    this.loadCount = 0;
    
    Object.values(IMG).forEach(img => this.loadImage(img)); // 遍历加载所有图片
  }

  loadImage(image) {
    let img = new Image();
    img.src = DIRECTORY + image;
    // 用箭头函数保证this指向Loader实例
    img.onload = () => {
      this.loadCount++;
      console.log('Loaded: ' + image);
      // 每次加载完成后检查是否全部加载完毕
      if (this.loadCount === this.imageCount) {
        console.log('Loaded images!');
        this.state.setState('loaded');
      }
    };
    // 新增加载失败处理,避免某张图加载失败导致永远无法触发状态变更
    img.onerror = () => {
      console.error('Failed to load: ' + image);
      this.loadCount++;
      // 即使加载失败,也检查是否所有任务都完成
      if (this.loadCount === this.imageCount) {
        console.log('All image load tasks finished (some failed)');
        this.state.setState('loaded');
      }
    };
  }
}

修改后的Manager.js

'use strict';
import { EventEmitter } from 'events'; // 修正EventEmitter的导入方式
import Canvas from './Canvas';
import Loader from './Loader';

class StateManager extends EventEmitter {
  constructor () {
    super();
    this.currentState = '';
  }

  setState(id) {
    this.currentState = id;
    console.log(`Current state: ${this.currentState}`);
    this.emit(id);
  }
}

export default class Manager {
  constructor() {
    this.init();
  }

  init() {
    this.state = new StateManager();
    // 绑定this到changeState,避免回调时this指向错误
    this.state.on('loaded', this.changeState.bind(this));
    this.Canvas = new Canvas();
    this.Loader = new Loader();
    this.Loader.setup(this.state);
  }

  changeState() {
    console.log('Loaded all content! Lets go!');
  }
}

关键优化说明

  • 修复异步判断逻辑:把加载完成的检查放到img.onload回调里,每次图片加载完成后都判断是否全部加载完毕,确保触发状态变更的时机正确。
  • 正确绑定this:用箭头函数或bind保证回调中的this指向正确的实例,避免出现属性找不到的问题。
  • 简化图片数量统计:用Object.values(IMG).length直接获取图片总数,减少手动累加的出错概率。
  • 添加错误处理:新增img.onerror回调,避免某张图片加载失败导致永远无法触发loaded事件。
  • 修正EventEmitter导入:原来的导入方式错误,改为从events模块正确导入EventEmitter类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:02:40