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

如何在JavaScript中实现类似XMLHttpRequest的自定义事件处理器

实现类似XMLHttpRequest的自定义事件处理器

嘿,我懂你要的效果——就是自己搞一个像XMLHttpRequest那样,能通过赋值onxxxx属性来监听多阶段状态变化的事件机制对吧?之前试了addEventListener和Promise没找到感觉,其实核心思路很简单:在自定义类里封装一个可赋值的回调属性,然后在状态变化时主动触发这个回调。

完整实现示例

我们来写一个模拟请求的CustomRequest类,完全复刻XHR的onreadystatechange逻辑:

class CustomRequest {
  // 私有字段存储回调函数,避免外部直接修改
  #onReadyStateChange = null;
  // 公开的状态属性,对应XHR的readyState
  readyState = 0;
  // 模拟HTTP状态码
  status = 0;

  // 定义可外部赋值的onreadystatechange属性
  get onreadystatechange() {
    return this.#onReadyStateChange;
  }

  set onreadystatechange(callback) {
    // 只接受函数类型的赋值,非函数则清空回调
    this.#onReadyStateChange = typeof callback === 'function' ? callback : null;
    // 可选:赋值后立即触发一次当前状态的回调
    this.#triggerCallback();
  }

  // 私有方法:触发回调,确保回调里的this指向当前实例
  #triggerCallback() {
    if (typeof this.#onReadyStateChange === 'function') {
      this.#onReadyStateChange.call(this);
    }
  }

  // 模拟请求发送过程,逐步改变状态
  send() {
    // 状态1:开始加载
    this.readyState = 1;
    this.#triggerCallback();

    // 用定时器模拟异步状态变化
    setTimeout(() => {
      this.readyState = 2; // 等待响应
      this.#triggerCallback();

      setTimeout(() => {
        this.readyState = 3; // 接收数据中
        this.#triggerCallback();

        setTimeout(() => {
          this.readyState = 4; // 请求完成
          this.status = 200; // 模拟成功状态码
          this.#triggerCallback();
        }, 500);
      }, 500);
    }, 500);
  }
}

使用方式(和XHR完全一致)

const req = new CustomRequest();
req.onreadystatechange = function() {
  switch (this.readyState) {
    case 0:
      console.log('未初始化');
      break;
    case 1:
      console.log('加载中');
      break;
    case 2:
      console.log('等待响应');
      break;
    case 3:
      console.log('接收数据中');
      break;
    case 4:
      if (this.status === 200) {
        console.log('请求成功!');
      }
      break;
  }
};

// 启动模拟请求
req.send();

为什么addEventListener/Promise没满足需求?

  • addEventListener:它是基于事件类型的订阅模式,适合多回调场景,但XHR的onreadystatechange是单一覆盖式的回调(每次赋值会替换之前的函数),和订阅模式逻辑不同;
  • Promise:它只能处理一次成功/失败的结果,无法适配像readyState这样的多阶段状态变化,所以天然不适合这种需要多次触发回调的场景。

可选优化点

  • 如果需要支持多个回调,可以把#onReadyStateChange改成数组,赋值时push函数,触发时遍历执行;
  • 可以添加其他类似XHR的回调属性,比如onload、onerror,逻辑和onreadystatechange一致;
  • 加入错误捕获,避免回调执行出错导致实例逻辑中断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 22:22:43