《Ajax - 实战基础篇》

在 Fetch 和 Axios 盛行的今天,为什么还要重学 XMLHttpRequest (XHR)?因为它是浏览器网络通信的基石。跳过底层直接学上层库,你得到的只是"术";理解 XHR,掌握的才是"道"。

本章将带你从概念到实战完成一次深度跨越:

  • 具象化理解:用生活类比讲透"异步"本质,告别死记硬背。
  • 掌控底层:拆解 XHR 生命周期与关键属性,提升调试排查能力。
  • 破解痛点:通过回调与 Promise 两种方案,彻底解决"异步数据外部无法使用"的经典难题。

💡 阅读提示 :建议打开浏览器控制台(F12),跟着代码亲手敲一遍。只有亲眼看到状态变化、亲手拿到数据,知识才能真正内化。让我们回到原点,重构你的 Ajax 认知体系。 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术

AJAX 通过在后台与服务器交换数据,并能够更新部分网页内容。
本次使用的编辑器为:webStorm 接口模拟使用的为:Apifox

以下为mock的Json数据,大家可以复制使用:

markdown 复制代码
{
  "code": 200,
  "message": "请求成功",
  "data": {
    "stationName": "华东第一光伏电站",
    "inspectionDate": "2026-10-26",
    "inspector": {
      "id": 1001,
      "name": "张三",
      "role": "高级工程师"
    },
    "devices": [
      {
        "deviceId": "PV-001",
        "type": "逆变器",
        "status": "normal",
        "metrics": {
          "voltage": 380.5,
          "current": 12.4,
          "temperature": 45.2
        },
        "lastMaintenance": "2026-09-15"
      },
      {
        "deviceId": "BAT-002",
        "type": "储能电池组",
        "status": "warning",
        "metrics": {
          "voltage": 220.1,
          "current": 0.0,
          "temperature": 62.8
        },
        "lastMaintenance": "2026-08-20",
        "remark": "温度略高,建议检查散热风扇"
      },
      {
        "deviceId": "INV-003",
        "type": "汇流箱",
        "status": "offline",
        "metrics": null,
        "lastMaintenance": "2026-10-01",
        "remark": "通讯模块故障,正在维修"
      }
    ],
    "summary": {
      "totalDevices": 3,
      "normalCount": 1,
      "warningCount": 1,
      "offlineCount": 1
    }
  }
}

APIfox大概设置步骤:

1. 核心概念拆解


  • 异步:这是Ajax的灵魂。传统的网页请求时"同步"的,即浏览器发送请求后必须等待服务器响应,期间页面会卡顿或刷新。而Ajax允许浏览器在后台与服务器交换数据,用户在此期间可以继续操作页面,不会感到终端。
  • JavaScript:用于发送请求和处理返回的数据。
  • XML:最初Ajax使用XML格式传输数据,但是现在常用的是JSON,因为它更轻量、更易解析。

2. Ajax的工作原理


想象一下你去餐厅吃饭:

  • 传统方式:你点完菜,必须站在柜台前一直等着,直到厨师做好菜端给你,你才能回到座位吃,这期间你没有办法去做别的事情
  • Ajax 方式(异步) :你点完菜后,回到座位继续聊天、喝水(继续浏览网页)。厨师做好菜后,服务员会把菜悄悄端到你桌上(后台更新数据),你不需要离开座位,也不需要重启整个用餐过程。

2.1. Ajax 的工作流程

  • 触发事件

    用户在网页上进行某种操作,例如:

    • 点击按钮
    • 输入框内容改变
    • 页面滚动到特定位置
    • 定时器触发
  • 创建请求对象

    JavaScript会创建一个用于与服务器通信的对象。

    • 传统方式:使用XMLHttpRequest对象。
    • 现在方式:使用fetch()函数或第三方库如Axios
  • 配置并发送请求

    开发者需要配置请求的细节,然后发送给服务器:

    • 请求方法method:GET(获取数据)、POST(提交数据)、Put、DELETE 等。
    • 请求地址URL:服务器的API接口地址。
    • 请求头Headers:设置内容类型、认证令牌等。
    • 请求体Body:如果POST请求,需要携带发送给服务器的数据(通常是JSON格式)。
  • 服务器处理

    服务器接收到请求后:

    • 解析请求参数。
    • 执行相应的业务逻辑(如查询数据库、计算数据)。
    • 生成响应数据(通常是 JSON 或 XML 格式)。
    • 返回 HTTP 状态码(如 200 OK, 404 Not Found, 500 Internal Server Error)。
  • 接收响应

    浏览器在后台接收到服务器的响应。

    注意:此时页面不会刷新,用户可以继续操作其他内容。

  • 处理响应数据

    JavaScript 通过回调函数、Promise 的 .then() 或 async/await 来处理响应:

    • 检查状态码 :确认请求是否成功(如判断 status === 200)。
    • 解析数据 :将返回的 JSON 字符串转换为 JavaScript 对象。
    • 错误处理:如果请求失败,执行相应的错误逻辑(如显示提示框)。
  • 更新DOM

    最后,JavaScript 使用解析后的数据来更新页面的特定部分:

    • 修改元素的文本内容 (innerText)。
    • 插入新的 HTML 元素 (innerHTML)。
    • 修改样式或属性。

3. XHR(XMLHttpRequest)


XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.

3.1 XHR的核心生命周期

状态 常量名 描述
0 UNSENT 代理被创建,但尚未调用 open() 方法。
1 OPENED open() 方法已被调用,准备发送请求。
2 HEADERS_RECEIVED send() 方法已被调用,且已接收到响应头(Headers)。
3 LOADING 正在下载响应体(Response Body),responseText 中可能已有部分数据。
4 DONE 请求操作已完成。无论成功还是失败,此时可以获取完整的响应数据。

在实际开发中我们一般关注状态4,因为这时的数据才能正常使用

3.2 标准的工作流程

一个完整的 XHR 请求包含以下五个核心步骤:

3.2.1. 实例化对象

ini 复制代码
const xhr = new XMLHttpRequest();

3.2.2. 初始化请求

open(method,url,async)方法用于配置请求的基本信息。

  • method:http方法,如GET,POST,PUT,DELETE 。
  • url:请求的目标地址。
  • async:true:表示异步(默认 );false:表示同步(严禁使用,会阻塞主线程导致页面卡死)
kotlin 复制代码
xhr.open('POST', 'https://api.example.com/login', true);

3.2.3. 设置请求头

在 open 之后、send() 之前调用。对于 POST 请求,通常需要告诉服务器发送的数据格式。

js 复制代码
// 告诉服务器我们要发送 JSON 数据
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
// 如果需要身份认证,通常会在这里添加 Token
xhr.setRequestHeader('Authorization', 'Bearer your_token_here');

3.2.4. 监听状态变化

这是处理响应的核心。由于是异步,我们需要一个回调函数来监听状态的改变。

js 复制代码
xhr.onreadystatechange = function() {
    // 只有当 readyState 为 4 且 status 为 200 时,才代表请求成功
    if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
            console.log('成功:', xhr.responseText);
            // 处理业务逻辑...
        } else {
            console.error('错误:', xhr.status, xhr.statusText);
        }
    }
};

3.2.5. 发送请求

  • GET 请求 :send() 括号内通常为空或 null。
  • POST 请求 :括号内传入要发送的数据字符串。如果是 JSON,需要先序列化。
js 复制代码
const data = JSON.stringify({ username: 'admin', password: '123' });
xhr.send(data);

3.2.6. 完整XHR的请求实例

js 复制代码
//创建xhr对象
const xhr = new XMLHttpRequest();  
//初始化请求
xhr.open("GET", 'https://m1.apifoxmock.com/m1/6778385-6490725-default/api/learnajax', true)  
//监听状态变化
xhr.onreadystatechange = () => {  
    if(xhr.readyState===4){  
        if(xhr.status >= 200 && xhr.status <300) {  
            let res = JSON.parse(xhr.responseText)  
            console.log('成功:',res)  
        }else{  
            console.log('错误:',xhr.status,xhr.statusText)  
        }    
    }
}          
//发送请求
xhr.send()

3.3 xhr对象的属性&&如何使用响应到的数据

通过以上的方式确实可以拿到对象形式的的响应数据,但是只能在这个响应中进行数据的操作,在外部是没有办法操作这些数据的,所以我们需要采用一些方法来使响应到的数据可以方便我们外部使用。

在这之前我需要和大家说一下,需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。

  • responseText:获得字符串形式的响应数据。
  • responseXML:获得 XML 形式的响应数据。

除此之外,还需要了解一些关于 xhr 对象的属性:

3.3.1 核心状态属性

  • readyState:4:

    • 含义:请求的当前阶段
    • 解读:4 代表 DONE(完成)。意味着整个请求过程已经结束(无论成功还是失败),数据已经接收完毕。
  • status:200:

    • 含义:HTTP 状态码。
    • 解读:200 代表 OK(成功)。服务器正常处理了请求并返回了数据。如果是 404 就是没找到,500 就是服务器报错。
  • statusText: ""

    • 含义:HTTP 状态文本。
    • 解读 :通常对应 status 的描述,比如 "OK" 或 "Not Found"。这里为空字符串可能是因为 Mock 服务器返回时未设置,或者浏览器解析差异,不影响逻辑,主要看 status 数字即可。

3.3.2. 响应数据属性

  • responseText: "{"code":200...":

    • 含义:服务器返回的原始文本数据(字符串格式)。
    • 解读 :这是最基础的属性。因为你的数据是 JSON 格式,所以它看起来像一串带转义字符的字符串。你需要用 JSON.parse(xhr.responseText) 把它变成 JS 对象才能方便使用。
  • response: {"code":200...:

    • 含义:解析后的响应体。
    • 解读 :注意看,这个属性里的内容已经是对象格式 了(没有外层引号)。这是因为现代浏览器比较智能,如果你设置了 xhr.responseType = 'json',或者浏览器自动推断出是 JSON,它会直接帮你解析好放在这里。建议优先使用 xhr.response 而不是 responseText,可以省去 parse 的步骤。
  • responseType: "":

    • 含义:你期望的响应类型。
    • 解读 :空字符串表示默认值(通常是文本)。如果你显式设置了 xhr.responseType = 'json',这里就会显示 'json'。
  • responseXML: null:

    • 含义:XML 格式的响应数据。
    • 解读 :因为你的接口返回的是 JSON 不是 XML,所以这里是 null。这个属性现在很少用了。
  • responseURL:

    • 含义:最终响应的 URL。
    • 解读:如果请求发生了重定向(Redirect),这里会显示重定向后的真实地址。

3.3.3. 事件回调属性 (监听器)

这些属性目前都是 null 或函数,代表你绑定的事件处理程序。

  • onreadystatechange: () => ... :

    • 解读 :这就是你代码里写的 xhr.onreadystatechange = () => {...}。因为它被赋值了,所以显示为一个箭头函数。
  • onload, onerror, ontimeout, onabort 等:

    • 解读 :这些都是 XHR 提供的其他事件钩子。

      • onload: 请求成功完成时触发(比 readyState 更好用)。
      • onerror: 网络错误时触发。
      • onprogress: 下载进度变化时触发。
    • 因为你代码里没写这些,所以它们显示为 null。

3.3.4. 其他配置与内部属性

  • withCredentials: false:

    • 含义:跨域请求是否携带 Cookie/认证信息。
    • 解读 :false 表示不携带。如果你的接口需要登录态(Cookie),通常需要设为 true。
  • timeout: 0:

    • 含义:超时时间(毫秒)。
    • 解读 :0 表示永不超时(直到浏览器自己断开)。
  • upload:

    • 含义:上传进度对象。
    • 解读 :用于监听文件上传的进度(xhr.upload.onprogress)。
  • [[Prototype]] :

    • 含义:原型链。
    • 解读 :这是 JS 对象的底层结构,指向 XMLHttpRequest.prototype,不用太关注。

3.3.5 如何去使用响应到的数据

上边就是xhr对象中的一些属性,建议大家理解即可,不用太执着某一点。接下来就一起来看一下如何去使用或者说是处理响应到的数据,首先响应到的数据只能在如下区域使用:

也就是说这部分代码会非常的冗余,臃肿,不易读。那么我们可定是更建议在外部去处理得到的数据。那么我这里提供两种方式,不是最好,但是好用,一个是通过回调函数取出数据,供外部使用,另一种是通过promise的方式。接下来就一个一个的演示。

3.3.5.1. 封装成函数并传入"回调函数"的方式
js 复制代码
/**  
 * 获取测试数据  
 * @param url 请求的地址  
 * @param callback 供内部调用,把数据传出,供外部使用  
 */  
function getAjaxData(url,callback) {  
    const xhr = new XMLHttpRequest();  
    xhr.open("GET", url, true)  
  
    xhr.onreadystatechange = () => {  
        if(xhr.readyState===4){  
            if(xhr.status >= 200 && xhr.status <300) {  
                let res = JSON.parse(xhr.responseText)  
                callback(null,res)  
            }else{  
                callback(new Error("请求失败"),null)  
                console.log('错误:',xhr.status,xhr.statusText)  
            }
        }    
    }    
    xhr.send();  
}  
  
//使用  
const Url = 'https://m1.apifoxmock.com/m1/6778385-6490725-default/api/learnajax';
getAjaxData(Url,(err,data)=>{  
    if (err) {  
        console.error(err);  
    } else {  
        console.log('我在外部拿到了数据:', data);  
    }
})
3.3.5.2. 使用Promise封装的方式
js 复制代码
/**  
 * 使用promise的方式  
 * @param url 请求的地址  
 * @returns {Promise<unknown>} 通过创建promise来获取  
 */  
function fetchWithXHR(url) {  
    return new Promise((resolve, reject) => {  
        const xhr = new XMLHttpRequest();  
        xhr.open("GET", url, true);  
        xhr.onreadystatechange = () => {  
            if(xhr.readyState === 4){  
                if(xhr.status >= 200 && xhr.status < 300) {  
		            resolve(JSON.parse(xhr.responseText)); 
		        }else {  
                    reject(new Error(`HTTP error! status: ${xhr.status}`));
                }
	        }       
	    };        
	    xhr.send();  
    });
}  
  
// 使用方式:配合 async/await 使用,看起来就像在等数据回来一样  
async function loadData() {  
    try {  
        const data = await fetchWithXHR('https://m1.apifoxmock.com/m1/6778385-6490725-default/api/learnajax');  
        console.log('拿到数据了,可以在这里随意使用:', data);  
    } catch (error) {  
        console.error('出错了:', error);  
    }}  
  
loadData();

4. 总结&&结语

4.1 总结

在本章中,我们完成了对 Ajax 技术从"概念认知"到"底层实战"的深度拆解。你不仅理解了 Ajax "异步交互、局部刷新"的核心灵魂,更通过 XMLHttpRequest (XHR) 这一经典 API,亲手触摸到了浏览器网络通信的脉搏。

我们重点掌握了以下核心技能:

  1. 生命周期掌控 :深入理解了 readyState 的五个阶段,明白了为何状态 4 是数据处理的黄金节点。
  2. 完整请求链路 :从实例化、配置请求头、监听状态变化到发送请求,构建了标准的 XHR 工作流。
  3. 响应数据解析 :学会了区分 responseText(原始字符串)与 response(自动解析对象),并了解了 status、withCredentials 等关键属性的实际意义。
  4. 异步数据突围 :突破了"回调函数内部才能使用数据"的限制,掌握了回调函数封装 与 Promise + async/await 两种现代化数据提取方案,为后续编写可维护的代码打下基础。

4.2. 结语

XHR 虽然诞生于 Web 早期,但它所蕴含的异步编程思想 和HTTP 交互模型 至今仍是所有现代前端框架(如 Vue、React)及网络库(如 Axios、Fetch)的基石。

学习建议: 不要将 XHR 视为"过时的老古董",而应将其作为理解浏览器底层机制的"解剖标本"。当你能熟练用 Promise 封装一个健壮的 XHR 请求时,你就已经具备了阅读 Axios 源码、理解微前端通信原理以及排查复杂网络问题的底层能力。

在接下来的章节中,我们将带着这份对底层的敬畏,迈向更简洁、更强大的 Fetch API 与 Axios 实战,让异步交互变得更加优雅高效。请保持这份探索欲,因为真正的进阶,往往始于对基础的极致理解。

相关推荐
gCode Teacher 格码致知1 小时前
前端教学8:提高 CSS 选择器的优先级,有哪些方法?
前端·css·html5
u0111026751 小时前
Canvas 导出 PNG 时 quality 参数为什么不起作用
前端·javascript·vue.js
众链网络1 小时前
年卡跨淡旺季的有效期模型:不可用日期、次数与顺延规则
java·前端·数据库
2601_949847752 小时前
jose 跨端三方库仓颉适配全流程
前端·javascript·flutter
CappuccinoRose2 小时前
滚动交互体系
前端·javascript·交互·html5·1024程序员节
时空节拍AI数字人2 小时前
博物馆数字人讲解系统设计:知识库 schema、展项联动协议与时序控制
java·服务器·前端·人工智能·ai·语音识别
吴建旭 智宅焕2 小时前
智能家居全国交付中前端工具与后端基础设施的系统集成架构:报价入口与交付兜底的闭环设计
前端·架构·智能家居
夏天要喝冰可乐2 小时前
Codex 写 Three.js 大屏实录:800 行代码,和一条画反的弧线
前端·aigc
欣欣之王来了2 小时前
v-bind语法糖::属性名的简写方式
前端·学习·架构·项目·vue3教程