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

为何改编MDN简单AJAX示例的代码出现回调重复触发问题?

问题的根源其实出在XMLHttpRequest的事件机制上

你遇到的这个多次触发的问题,根本不是点击事件触发了多次——毕竟你已经加了{once: true}确保点击只会触发一次getData。真正的原因是你对onreadystatechange事件的理解有误:

这个事件会在XMLHttpRequest对象的readyState属性发生任何变化时触发,而不是只在请求完成时触发。XMLHttpRequest一共有5种readyState状态:

  • 0: UNSENT(对象已创建但还没调用open)
  • 1: OPENED(open方法已调用)
  • 2: HEADERS_RECEIVED(send方法已调用,响应头已返回)
  • 3: LOADING(响应体正在下载中)
  • 4: DONE(请求彻底完成)

你的handleData函数没有做任何状态判断,所以每一次readyState变化,它都会被执行一次。比如正常情况下,一个AJAX请求会依次触发readyState从1到4的变化,也就是会调用4次handleData——这也解释了为什么你加了循环后会看到4组输出。而你之前看到的两次输出,可能是某些状态在你的测试环境中没有触发(比如有些浏览器可能会合并部分状态变化),但本质还是同一个问题。

再看看你参考的MDN示例,人家的alertContents函数开头就加了if (httpRequest.readyState === XMLHttpRequest.DONE)的判断,只有当请求彻底完成时才执行后续逻辑,所以只会触发一次。

解决办法

你有两种选择来修复这个问题:

  1. 照搬MDN的思路,在handleData里先判断readyState是否为DONE:
function handleData() {
  if (httpRequest.readyState === XMLHttpRequest.DONE) {
    console.log("Handling data");
    // 这里再处理你的响应数据
  }
}
  1. 改用onload事件代替onreadystatechange,这个事件只会在请求成功完成(readyState=4且status=200)时触发:
// 把原来的 httpRequest.onreadystatechange = handleData; 改成
httpRequest.onload = handleData;

function handleData() {
  console.log("Handling data");
  // 直接处理响应即可
}

这样就能确保handleData只会被执行一次啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:42:29