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

JavaScript中XMLHttpRequest回调多次执行问题排查

问题现象

最开始以为代码中onreadystatechange里的if和else代码块都会被执行,添加debugger断点调试后,发现代码实际会多次运行,不清楚具体原因,复现代码如下:

复现代码

JS逻辑

function Submit(form) {
  var timer_starttime = document.getElementById("timer_starttime");
  var timer_finishtime = document.getElementById("timer_finishtime");
  if (wait_s.reportValidity() && wait_m.reportValidity()) {
    var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance 
    var theUrl = "/submit_program";
    xmlhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        //document.getElementById("ajax_res").innerHTML = this.responseText;
        document.getElementById("success-alert").className = "alert alert-success alert-dismissible";
        console.log(this.responseText);
        console.log("if");
        debugger;
      } else {
        document.getElementById("error-alert").className = "alert alert-danger alert-dismissible";
        console.log("else");
      }
    };
    xmlhttp.open("POST", theUrl);
    xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xmlhttp.send(JSON.stringify({
      "timer_finishtime": timer_finishtime.value,
      "timer_starttime": timer_starttime.value
    }));
  }
  return false;
}
console.log("end");

表单HTML

<form id="TimeForm" action="" method="POST">
  ...
  <button type="submit" class="btn btn-primary" onclick="return Submit(this);">Save</button>
</form>
问题原因

出现该现象的核心原因是对XMLHttpRequest的onreadystatechange事件触发逻辑存在认知偏差:

  • 该事件并非在请求结束时仅触发1次,而是会在请求的每一个生命周期状态发生变化时触发,一个正常请求从初始化到完成,回调至少会触发4次。
  • XMLHttpRequest的readyState属性对应5个请求阶段:
    • 0:请求未初始化,尚未调用open()方法
    • 1:服务端连接已建立,open()方法调用完成
    • 2:请求已发送,send()方法调用完成,已接收全部响应头
    • 3:正在接收响应体,响应内容处于传输解析过程中
    • 4:请求全部完成,整个响应接收完毕
  • 现有判断逻辑为:只要不满足readyState == 4 && status == 200就进入else分支,请求处于0、1、2、3这几个中间状态触发回调时,都会进入else分支打印日志,等最后请求完成且状态码正常时才进入if分支,因此会观察到代码多次运行、if和else分支都有输出的现象。
  • 该逻辑还存在额外问题:请求传输过程中就会给错误提示框添加显示样式,会导致请求正常时用户也能看到错误提示。
修复方案

调整回调里的判断顺序,先判断请求是否已经完成,只有请求完成后再根据状态码判断是成功还是失败,中间状态不做任何业务处理:

xmlhttp.onreadystatechange = function() {
  // 中间状态直接返回,不做处理
  if (this.readyState !== 4) return;

  if (this.status === 200) {
    document.getElementById("success-alert").className = "alert alert-success alert-dismissible";
    console.log(this.responseText);
    console.log("请求成功");
    debugger;
  } else {
    // 只有请求完成但状态码异常时才显示错误提示
    document.getElementById("error-alert").className = "alert alert-danger alert-dismissible";
    console.log("请求失败,状态码:" + this.status);
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:12:18