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

如何获取XMLHttpRequest的event.loaded并dispatch到state实现网速测试

问题原因

你当前代码拿不到正确下载大小的核心问题有3个:

  • onprogress 是事件绑定的回调函数,函数内部的return不会向外传递值,你写return event.loaded没有任何实际作用
  • 你在请求完成时resolve(xhr.onprogress),传递的是回调函数本身,不是下载过程中记录的字节数值
  • 没有单独的变量持久化存储每次进度回调返回的event.loaded,请求结束时自然拿不到最终的总下载字节数
修正实现

你只需要在XHR请求内部维护一个存储最新下载字节数的变量,每次onprogress触发时更新这个变量,同时可以直接dispatch进度到store做实时速度计算,等请求完成时把最终的字节数resolve出去即可,修正后的完整代码如下:

const startSpeedTestAsync = () => async (dispatch: Dispatch) => {
  const url = config.SPEED_TEST;
  dispatch(setLoadTest(true));
  const startTime = new Date().getTime();
  dispatch(startSpeedTest({ startTime, isShowInfo: false }));

  let finalLoaded = 0;
  const endRequest = (error?: unknown) => {
    const endTime = new Date().getTime();
    dispatch(setEndTime(endTime));
    dispatch(calcSpeed(error ? 0 : finalLoaded));
    dispatch(stopSpeedTest({ isLoadTest: false, isShowInfo: true }));
  };

  const sendHttpRequest = (method: string, currentUrl: string) => {
    const promise: Promise<number> = new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.timeout = 5000;

      xhr.onprogress = function (event) {
        finalLoaded = event.loaded;
        // 如需实时计算瞬时网速,可在此处派发进度action
        // dispatch(updateSpeedProgress({ loaded: event.loaded, time: Date.now() }));
        console.log('loaded: ', event.loaded);
      };

      xhr.onreadystatechange = function () {
        if (xhr.readyState !== 4) return;
        // 请求完成后判断状态码,2xx代表正常响应
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(finalLoaded);
        } else {
          reject(new Error(`Request failed with status ${xhr.status}`));
        }
      };

      // 绑定超时、错误回调,避免Promise挂起
      xhr.ontimeout = () => reject(new Error('Request timeout'));
      xhr.onerror = () => reject(new Error('Network error'));

      xhr.open(method, currentUrl);
      xhr.send();
    });
    return promise;
  };

  sendHttpRequest('GET', url)
    .then((loadedSize) => {
      console.log('最终下载字节数:', loadedSize);
      endRequest();
    })
    .catch((err) => {
      console.error('测速失败:', err);
      endRequest(err);
    });
};
注意事项
  • 测速使用的资源建议选大小在1MB以上的静态文件,文件过小会导致onprogress只触发1-2次,计算出的网速误差极大
  • 如果需要更精准的实时网速,可以在onprogress回调里记录每次触发的时间戳,用两次进度回调的字节差 / 时间差计算瞬时速度,比总大小/总时间的结果更贴近真实体验
  • 测速资源需要配置跨域响应头,否则XHR请求会被浏览器跨域策略拦截,无法正常触发进度事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:57:27