news 2026/4/23 13:24:18

Ajax、XMLHttpRequest(XHR) 、Promise、Fetch、Axios 的区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ajax、XMLHttpRequest(XHR) 、Promise、Fetch、Axios 的区别

在现代Web开发中,AjaxXMLHttpRequest(XHR)PromiseFetchAxios,这几个词虽然都跟“前端发送网络请求”相关,但它们的层次和定位截然不同。

1. 一句话概览关系

  • Ajax是一种技术概念/模式,不是具体的API或库。(目的:无刷新更新页面)

  • XHRFetch是浏览器提供的原生底层工具。(手段:怎么把请求发出去)

  • Promise是 JavaScript 处理异步逻辑的语法规范。(工具:怎么管理回调)

  • Axios是基于Promise并封装了XHR/Fetch第三方库。(目的:让发请求更舒服)


2. 详细拆解与举例

① Ajax (Asynchronous JavaScript And XML)
  • 本质:不是具体的 API,而是一套技术组合拳。2005 年 Jesse James Garrett 提出,指利用XMLHttpRequest对象在后台与服务器交换数据,并通过 DOM 操作局部更新页面。

  • 核心特点异步执行+无刷新。通常依赖XMLHttpRequest对象(或Fetch API)来实现异步通信。它允许网页在不重新加载的情况下,与服务器交换数据并更新部分网页内容。

  • 现状:虽然名字带 XML,但现在 99% 的情况是用 JSON 格式。

② XHR (XMLHttpRequest)
  • 本质:浏览器提供的原生构造函数,是实现 Ajax 最古老的底层 API。

  • 写法特征:基于事件监听onreadystatechangeonload),容易陷入回调地狱(Callback Hell)。

构造函数

const xhr = new XMLHttpRequest();

创建一个 XHR 实例,在调用任何其他方法前必须先实例化

主要属性
属性类型说明
readyState只读 number请求状态:0=UNSENT(未调用 open),1=OPENED(已调用 open),2=HEADERS_RECEIVED(已接收响应头),3=LOADING(接收响应体中),4=DONE(完成)-1
status只读 numberHTTP 响应状态码(200、404、500 等)
statusText只读 stringHTTP 状态文本("OK"、"Not Found" 等)
response只读 any响应体,类型由responseType决定
responseText只读 string字符串格式的响应体(当responseType为空或 "text" 时)
responseXML只读 Document以 XML 文档形式解析的响应
responseTypestring指定响应数据类型:""(文本)、"arraybuffer"、"blob"、"document"、"json"、"text"
timeoutnumber超时时间(毫秒),超时后触发ontimeout事件
withCredentialsboolean跨域请求是否携带 Cookie,默认 false
upload只读 XMLHttpRequestUpload上传对象,可监听上传进度事件
主要方法
方法说明
open(method, url, async, user, password)初始化请求。async默认为 true(异步),设为 false 会阻塞主线程(不推荐)-3
send(body)发送请求。GET/HEAD 请求通常不传 body
setRequestHeader(name, value)设置请求头,必须在open()之后、send()之前调用
getResponseHeader(name)获取指定响应头的值
getAllResponseHeaders()获取所有响应头(CRLF 分隔的字符串)
abort()取消请求,触发onabort事件
overrideMimeType(mime)强制指定响应 MIME 类型
主要事件
事件说明
onreadystatechange每当readyState变化时触发
onload请求成功完成时触发(等价于readyState === 4且状态成功)-6
onerror网络层面错误(DNS 失败、断网等)时触发
onprogress接收数据时周期性触发,可获取下载进度
onloadstart/onloadend请求开始/结束时触发
ontimeout超时时触发
onabort调用abort()取消请求时触发
upload.onprogress上传进度事件,用于监控上传进度

代码示例:

const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.example.com/data'); // 必须监听状态变化 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log('成功', JSON.parse(xhr.responseText)); } else { console.log('失败'); } } }; xhr.send();
// XHR 详细示例 function xhrExample() { // 创建 XMLHttpRequest 对象 const xhr = new XMLHttpRequest(); // 配置请求 xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true); // 设置请求头(可选) xhr.setRequestHeader('Content-Type', 'application/json'); // 监听状态变化 xhr.onreadystatechange = function() { // readyState: 0=未初始化, 1=正在打开, 2=已发送, 3=接收中, 4=完成 if (xhr.readyState === 4) { if (xhr.status === 200) { // 成功 document.getElementById('xhrResult').innerHTML = '<h3>XHR 成功</h3><pre>' + JSON.stringify(JSON.parse(xhr.responseText), null, 2) + '</pre>'; document.getElementById('xhrResult').style.display = 'block'; } else { // 失败 document.getElementById('xhrResult').innerHTML = '<h3>XHR 失败</h3><p>状态码: ' + xhr.status + '</p>'; document.getElementById('xhrResult').style.display = 'block'; } } }; // 错误处理 xhr.onerror = function() { document.getElementById('xhrResult').innerHTML = '<h3>XHR 网络错误</h3>'; document.getElementById('xhrResult').style.display = 'block'; }; // 发送请求 xhr.send(); }
//基础 GET 请求: // 1. 创建实例 const xhr = new XMLHttpRequest(); // 2. 初始化请求(GET + 异步) xhr.open('GET', 'https://api.example.com/users/1', true); // 3. 设置响应类型(自动解析 JSON) xhr.responseType = 'json'; // 4. 设置超时 xhr.timeout = 5000; // 5. 监听事件 xhr.onload = function() { // onload 只在请求成功时触发 if (xhr.status >= 200 && xhr.status < 300) { console.log('请求成功:', xhr.response); } else { console.error('HTTP 错误:', xhr.status); } }; xhr.onerror = function() { console.error('网络错误或跨域问题'); }; xhr.ontimeout = function() { console.error('请求超时'); }; // 6. 发送请求 xhr.send();
//POST 请求(发送 JSON): const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.example.com/users', true); // 设置请求头 xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { console.log('创建成功:', JSON.parse(xhr.responseText)); } }; const payload = { name: '张三', age: 25 }; xhr.send(JSON.stringify(payload));
//上传进度监控: const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.example.com/upload', true); const formData = new FormData(); formData.append('file', fileInput.files[0]); // 监听上传进度 xhr.upload.onprogress = function(event) { if (event.lengthComputable) { const percent = (event.loaded / event.total) * 100; console.log(`上传进度: ${percent.toFixed(2)}%`); } }; xhr.onload = function() { console.log('上传完成'); }; xhr.send(formData);
XHR 工作流程
创建对象 → open() 配置请求 → send() 发送请求 → 监听状态变化 → 处理响应
readyState 含义
含义
0初始化
1open 已调用
2收到响应头
3接收数据中
4请求完成
③ Promise
  • 本质:ES6 引入的语法标准,用于解决异步回调嵌套问题。

  • 关键点:Promise 本身不是用来发请求的,而是用来包装异步操作的容器。Fetch 和 Axios 都使用了 Promise 作为返回值。

代码示例(用 Promise 包装 XHR):

function request(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = () => resolve(xhr.response); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); } // 使用 then/catch 链式调用,告别回调地狱 request('/api').then(data => console.log(data));
//Promise 示例(模拟请求) const fetchData = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: 1, name: 'Qwen' }); }, 1000); }); }; fetchData().then(data => console.log(data));
Promise 三种状态
状态含义
pending进行中
fulfilled成功
rejected失败
④ Fetch API
  • 本质:浏览器提供的第二代原生请求 API,替代 XHR。

  • 核心特征

    1. 基于 Promise,语法简洁现代。

    2. 默认不携带 Cookie(需设置credentials: 'include')。

    3. 只会在网络故障时 reject,对于 404、500 这类 HTTP 错误状态码,Fetch 依然会认为请求成功(resolve),需要手动判断response.ok

fetch() 函数:

fetch(resource, init)

  • resource:请求 URL 或 Request 对象

  • init:可选配置对象,包含以下常用字段:

配置项类型说明
methodstringHTTP 方法:GET、POST、PUT、DELETE 等
headersobject/Headers请求头对象,如{ 'Content-Type': 'application/json' }
bodystring/FormData/Blob 等请求体,GET/HEAD 不能有 body
modestring跨域模式:"cors"(默认)、"no-cors"、"same-origin"
credentialsstring凭证策略:"omit"(默认,不带 Cookie)、"same-origin"(同域带)、"include"(始终带)-16
cachestring缓存策略:"default"、"no-store"、"reload" 等
redirectstring重定向处理:"follow"(默认)、"error"、"manual"
signalAbortSignal用于取消请求
Response 对象

fetch()返回的 Promise 会 resolve 为 Response 对象,包含以下常用属性和方法:

属性/方法说明
response.okboolean,状态码 200-299 时为 true-15
response.statusHTTP 状态码
response.statusText状态文本
response.headersHeaders 对象
response.json()解析 JSON,返回 Promise
response.text()读取为文本,返回 Promise
response.blob()读取为 Blob,返回 Promise
response.formData()读取为 FormData,返回 Promise
response.arrayBuffer()读取为 ArrayBuffer,返回 Promise
response.bodyReadableStream,可用于流式读取

代码示例:

fetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: 1 }) }) .then(response => { // 注意:必须手动检查 status! if (!response.ok) { throw new Error('HTTP error ' + response.status); } return response.json(); // 这也是个 Promise }) .then(data => console.log('Fetch 结果', data)) .catch(err => console.log('网络挂了或逻辑错误', err));
// Fetch 详细示例 async function fetchExample() { try { // 发起请求 const response = await fetch('https://jsonplaceholder.typicode.com/posts/1', { method: 'GET', headers: { 'Content-Type': 'application/json', // 'Authorization': 'Bearer your-token' // 如需要认证 }, // credentials: 'include', // 包含cookies }); // 检查响应状态 if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // 解析 JSON 数据 const data = await response.json(); document.getElementById('fetchResult').innerHTML = '<h3>Fetch 成功</h3><pre>' + JSON.stringify(data, null, 2) + '</pre>'; document.getElementById('fetchResult').style.display = 'block'; } catch (error) { document.getElementById('fetchResult').innerHTML = '<h3>Fetch 错误</h3><p>错误信息: ' + error.message + '</p>'; document.getElementById('fetchResult').style.display = 'block'; } }
//基础 GET 请求: async function getUser(id) { try { const response = await fetch(`https://api.example.com/users/${id}`); // Fetch 不会因 HTTP 错误而 reject,需手动检查 if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); console.log('用户数据:', data); return data; } catch (error) { console.error('请求失败:', error.message); } }
//POST 请求(发送 JSON) async function createUser(userData) { try { const response = await fetch('https://api.example.com/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(userData) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || '创建失败'); } const newUser = await response.json(); console.log('创建成功:', newUser); return newUser; } catch (error) { console.error('请求失败:', error); } } createUser({ name: '李四', email: 'lisi@example.com' });
//带 Cookie 的跨域请求: async function fetchWithCredentials(url) { const response = await fetch(url, { credentials: 'include' // 跨域请求也携带 Cookie }); return response.json(); }
//超时控制(使用 AbortController): function fetchWithTimeout(url, timeout = 8000) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); return fetch(url, { signal: controller.signal }) .finally(() => clearTimeout(timeoutId)); } // 使用 try { const response = await fetchWithTimeout('https://api.example.com/slow-endpoint', 5000); const data = await response.json(); } catch (error) { if (error.name === 'AbortError') { console.error('请求超时'); } else { console.error('其他错误:', error); } }
⑤ Axios
  • 本质第三方 HTTP 库。在浏览器端它底层调用的是XHR,在 Node.js 端调用的是http 模块

  • 为什么用 Axios 而不是直接用 Fetch?

    • 自动 JSON 转换:不用写两次then或手动JSON.parse

    • 请求/响应拦截器:可以在请求前统一加 Token,或在响应后统一处理报错。

    • 取消请求:提供了CancelTokenAbortController的简单封装。

    • 超时设置:Fetch 本身不支持超时配置,Axios 可以直接配timeout

基本请求方法:

axios(config) // 通用请求 axios.get(url, config) axios.post(url, data, config) axios.put(url, data, config) axios.patch(url, data, config) axios.delete(url, config) axios.head(url, config) axios.options(url, config) axios.request(config) // 等同于 axios(config)
请求配置(config)常用字段:
配置项类型说明
urlstring请求 URL
methodstring请求方法(默认 GET)
baseURLstring基础 URL,会与url拼接
headersobject自定义请求头
paramsobjectURL 查询参数,自动序列化
dataany请求体数据,对象会自动序列化为 JSON
timeoutnumber超时时间(毫秒)
withCredentialsboolean跨域请求是否携带 Cookie
responseTypestring响应数据类型:"json"(默认)、"blob"、"text" 等
cancelTokenCancelToken用于取消请求(已废弃,推荐使用signal
signalAbortSignal取消请求(与 Fetch 兼容)

代码示例:

// 1. 配置拦截器(全局操作) axios.interceptors.request.use(config => { config.headers.Authorization = `Bearer token`; return config; }); // 2. 发送请求 axios.post('/api/data', { name: 'DeepSeek' }) .then(response => { // 这里的 response.data 已经是解析好的对象,且 4xx/5xx 会自动进 catch console.log(response.data); }) .catch(error => { // Axios 自动处理了 HTTP 错误状态码 console.log('请求失败', error.response?.status); });
// Axios 详细示例 async function axiosExample() { try { // 发起请求 const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1', { headers: { 'Content-Type': 'application/json', // 'Authorization': 'Bearer your-token' // 如需要认证 }, timeout: 5000, // 超时时间 }); // 直接访问数据(Axios自动解析JSON) const data = response.data; const status = response.status; const headers = response.headers; document.getElementById('axiosResult').innerHTML = '<h3>Axios 成功</h3>' + '<p>状态码: ' + status + '</p>' + '<pre>' + JSON.stringify(data, null, 2) + '</pre>'; document.getElementById('axiosResult').style.display = 'block'; } catch (error) { let errorMsg = '未知错误'; if (error.response) { // 服务器响应了错误状态码 errorMsg = `服务器错误: ${error.response.status} - ${error.response.statusText}`; } else if (error.request) { // 请求已发出但没有收到响应 errorMsg = '网络错误或请求超时'; } else { // 其他错误 errorMsg = error.message; } document.getElementById('axiosResult').innerHTML = '<h3>Axios 错误</h3><p>错误信息: ' + errorMsg + '</p>'; document.getElementById('axiosResult').style.display = 'block'; } }
import axios from 'axios'; // 使用 AbortController(推荐,与 Fetch 统一) const controller = new AbortController(); axios.get('/api/data', { signal: controller.signal }) .then(response => console.log(response)) .catch(error => { if (axios.isCancel(error)) { console.log('请求已取消'); } }); // 取消请求 controller.abort();

3. 核心区别对比表

维度XHRFetchAxios
类型原生 API原生 API第三方库 (需安装)
参数处理需手动序列化/反序列化 JSON需两次then解析 JSON自动转换 JSON
错误判定status200-299 算成功仅网络错误 rejectHTTP 错误自动 reject
超时控制支持xhr.timeout原生不支持(需结合 AbortController)支持timeout参数
请求进度支持onprogress(可做上传进度条)不支持上传进度支持 (浏览器端)
拦截器强大
取消请求xhr.abort()AbortController(稍繁琐)

CancelToken/AbortController

异步机制

事件监听(回调)

(非Promise)

Promise + async/awaitPromise + async/await
跨域 CookiewithCredentials = truecredentials: 'include'withCredentials: true

​​

Ajax是指导思想,XHR是老旧实现,Fetch是现代原生实现但功能简陋,Promise是异步流程控制工具,而Axios是基于 Promise 对请求的工业级封装。

  • 简单脚本或 PWA:直接用Fetch足矣(注意记得检查res.ok)。

  • 复杂后台管理系统 / 全栈项目Axios是事实标准,它的拦截器和自动 JSON 处理能极大减少样板代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:12:50

番茄小说下载器完整指南:永久保存心爱小说的终极解决方案

番茄小说下载器完整指南&#xff1a;永久保存心爱小说的终极解决方案 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 还在为番茄小说中的精彩内容担心下架而烦恼吗&#xff1f;fanqienovel…

作者头像 李华
网站建设 2026/4/23 13:12:43

告别Arduino IDE:在ESP-IDF下用ESP32+CNC Shield驱动步进电机的完整配置流程

从Arduino到ESP-IDF&#xff1a;ESP32驱动CNC Shield与A4988的深度迁移指南 当你的步进电机项目需要更精确的控制、更高效的性能或更复杂的多轴协同&#xff0c;Arduino IDE可能开始显得力不从心。这正是许多开发者转向ESP-IDF的转折点——乐鑫官方为ESP32打造的物联网开发框架…

作者头像 李华
网站建设 2026/4/23 13:12:38

pyNastran终极指南:从BDF/OP2到VTK的高效转换与可视化

pyNastran终极指南&#xff1a;从BDF/OP2到VTK的高效转换与可视化 【免费下载链接】pyNastran A Python-based interface tool for Nastrans file formats 项目地址: https://gitcode.com/gh_mirrors/py/pyNastran pyNastran作为处理NASTRAN文件的Python工具包&#xff…

作者头像 李华
网站建设 2026/4/23 13:11:46

突破传统:当视频字幕制作遇见智能革命

突破传统&#xff1a;当视频字幕制作遇见智能革命 【免费下载链接】video-srt-windows 这是一个可以识别视频语音自动生成字幕SRT文件的开源 Windows-GUI 软件工具。 项目地址: https://gitcode.com/gh_mirrors/vi/video-srt-windows 你是否曾为视频字幕制作而苦恼&…

作者头像 李华