从零掌握 Ajax:一次请求带你读懂异步数据加载原理

一、精炼理解:Ajax 到底是啥?

Ajax = 在不刷新页面的情况下,和服务器交换数据并动态更新页面

它让 Web 页面拥有"应用级"的体验------局部更新、响应式交互、更少等待。核心实现长期基于浏览器内建对象 XMLHttpRequest(XHR) ,现代开发则多用 fetch / Axios,但底层思想相同:异步请求 + 数据驱动视图


二、核心流程

  1. 创建 XHR 实例

    ini 复制代码
    const xhr = new XMLHttpRequest();
  2. 打开连接

    kotlin 复制代码
    xhr.open('GET', '/api/members', true); // true => 异步
  3. 可选:设置请求头 / 超时 / 响应类型

    ini 复制代码
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.responseType = 'json'; // 直接得到对象(现代浏览器)
    xhr.timeout = 5000; // 毫秒
  4. 发送请求

    ini 复制代码
    xhr.send();
  5. 监听状态 / 处理响应

    ini 复制代码
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          const data = xhr.responseType === 'json' ? xhr.response : JSON.parse(xhr.responseText);
          // 更新 DOM
        } else {
          // 处理非 200 的情况
        }
      }
    };
  6. 清理/取消

    arduino 复制代码
    xhr.abort(); // 主动取消请求

三、readyState 一眼看懂

  • 0 UNSENT:未调用 open()
  • 1 OPENED:调用了 open(),可 setRequestHeadersend
  • 2 HEADERS_RECEIVED:已接收响应头(可读取 status)
  • 3 LOADING:接收响应体中(可处理流式数据)
  • 4 DONE:响应完成,数据就绪

调试建议 :打印 readyStatestatus,快速定位在哪个阶段失败。


四、常见坑与解决方法

1. 同步请求会卡死 UI

xhr.open(..., false) 是同步,会阻塞主线程。不要在浏览器中使用同步请求,除非你非常清楚场景(几乎没有)。

2. 跨域(CORS)错误

浏览器会阻止不满足 CORS 策略的请求。后端需设置 Access-Control-Allow-Origin,或通过代理绕过开发时限制。

3. JSON 解析报错

JSON.parse 报错说明服务器没返回合法 JSON。排查响应 Content-Type、响应体首尾空白和服务器异常栈。

4. 超时与重试

设置合理 xhr.timeout,并在 ontimeout 中进行用户提示或重试逻辑(避免无限重试)。

5. 状态码不是 200

处理 4xx/5xx、304 等不同类型响应,给用户明确提示而非只在控制台打印错误。

6. 网络抖动与幂等

POST 请求若可重试需保证幂等(或在服务端做去重),避免重复提交造成的数据问题。


五、XHR 与 fetch/Axios 对比(实用速览)

特性 XHR fetch Axios
语法风格 回调/事件 Promise(更现代) Promise + 自动 JSON 处理
支持流 有(onprogress) 有(ReadableStream) 基于 fetch/XHR,封装更好
自动 JSON 解析 .json() 是(响应自动转换)
超时设置 有(timeout 需 AbortController 内置超时配置
更灵活的进度 是(上传/下载 progress) 比较复杂 封装上传/下载进度支持

建议:新项目优先用 fetch 或 Axios;但遇到上传进度/低层控制时,XHR 的事件模型仍然非常有用。


六、实用示例:可靠的异步请求

ini 复制代码
<ul id="members"></ul>
<script>
  const ul = document.getElementById('members');

  function fetchMembers() {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://api.github.com/orgs/lemoncode/members', true);
    xhr.responseType = 'json'; // 现代浏览器直接得到对象
    xhr.timeout = 7000;

    xhr.onreadystatechange = () => {
      if (xhr.readyState !== 4) return;
      if (xhr.status === 200) {
        const data = xhr.response;
        ul.innerHTML = data.map(u => `<li>${u.login}</li>`).join('');
      } else {
        ul.innerHTML = `<li>请求失败:${xhr.status} ${xhr.statusText}</li>`;
      }
    };

    xhr.ontimeout = () => {
      ul.innerHTML = '<li>请求超时,请重试</li>';
    };

    xhr.onerror = () => {
      ul.innerHTML = '<li>网络错误,请检查连接</li>';
    };

    xhr.send();
    return xhr; // 若需要外部取消请求,可保留此引用并调用 xhr.abort()
  }

  fetchMembers();
</script>

七、总结

掌握 Ajax,不只是知道如何发请求,而是理解请求生命周期、错误处理与用户体验折衷------把网络的不确定性,优雅地交给代码去处理。

相关推荐
qq_26761289几秒前
项目集、里程碑与迭代联动:Gitee项目管理如何支撑多团队规模化交付与进度风险治理
前端·gitee
赵广陆13 分钟前
企业实战:Web服务端搭建
前端·langchain·langgraph
常宇佳16 分钟前
vue3 实战系列之无法识别vue组件
前端·javascript·vue.js
掘金者阿豪24 分钟前
Codex 怎么突然变慢了?一个需求跑几十分钟,我才发现它的工作方式已经变了
前端·后端
用户9314563556629 分钟前
从 3 秒到 300 毫秒:一次真实的前端首屏性能优化全记录
前端
whn197730 分钟前
dm9安装初体验
前端
阿黎梨梨36 分钟前
从零搞懂 JWT 登录鉴权:一张“电子通行证”的诞生记
前端
全栈项目管理程序猿36 分钟前
ArcGIS JS 基础教程(12):视图截图 takeScreenshot
javascript
用户9210802628636 分钟前
ChatMessageList 消息列表组件:基于 BubbleList 搭建 AI 对话展示区
前端
HjhIron40 分钟前
实战 React + JWT + Zustand:从零搭建登录鉴权系统
前端