从 XMLHttpRequest 到 Fetch:AJAX 请求的演进与最佳实践

🌟 AJAX:让网页"静悄悄"获取数据的魔法

前言:认识AJAX

AJAX (Asynchronous JavaScript and XML) 是前端开发中一项革命性的技术,它让网页能够在不刷新页面的情况下与服务器交换数据并更新部分内容。想象一下:当你在音乐APP点击"新歌速递"时,整个页面不会闪屏刷新,新歌列表就像变魔术一样悄然出现------这就是AJAX的魔力!

AJAX的三大特点:

  1. 异步通信:不会阻塞用户操作
  2. 局部更新:只刷新需要变化的部分
  3. 多种数据格式:不仅限于XML,更常用JSON

正文:手把手教你实现AJAX请求

一、基础AJAX代码解析

我们以获取网易云音乐新歌列表为例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>音乐速递</title>
</head>
<body>
    <button id="btn">新歌速递</button>
    <ul id="song-list"></ul>

    <script>
        const btn = document.getElementById('btn');
        btn.addEventListener('click', () => {
            // 1. 创建XMLHttpRequest对象
            let xhr = new XMLHttpRequest();
            
            // 2. 配置请求 (演示用示例地址,实际需替换为真实API)
            xhr.open('GET', 'https://api.example.com/top/songs?type=7', true);
            
            // 3. 设置回调函数
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    const result = JSON.parse(xhr.responseText);
                    
                    // 4. 动态更新DOM
                    const songList = document.getElementById('song-list');
                    result.data.forEach(song => {
                        // console.log(song.name);
                        let li = document.createElement('li'); // 创建一个 <li> 元素
                        li.innerHTML = song.name  // 将歌曲的名称设置为 <li> 元素的内容
                        document.getElementById('ul').appendChild(li) 
                        //appendChild添加子元素  将 <li> 元素追加到具有 id 为 'ul' 的元素中
                    });
                }
            };
            
            // 5. 发送请求
            xhr.send();
        });
    </script>
</body>
</html>

二、关键知识点详解

1. XMLHttpRequest 对象
  • new XMLHttpRequest():创建请求对象
  • open(method, url, async):配置请求
    • GET/POST:请求方法
    • 真实开发中地址应替换为后端提供的API(如:https://api.music-service.com/v1/songs
    • 第三个参数true表示异步(推荐永远用异步!)
2. 请求状态监听
javascript 复制代码
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        // 请求完成且成功
    }
};
  • readyState

    • 0: 请求未初始化
    • 1: 服务器连接已建立
    • 2: 请求已接收
    • 3: 处理请求中
    • 4: 请求已完成
  • status:HTTP状态码(200表示成功)

3. 处理响应数据
  • xhr.responseText:获取字符串格式响应
  • JSON.parse():将JSON字符串转为JS对象
4. 安全注意事项
  • 实际开发中要处理错误情况:

    javascript 复制代码
    if (xhr.status >= 200 && xhr.status < 300) {
        // 成功处理
    } else {
        console.error('请求失败:', xhr.statusText);
    }
  • 跨域问题:如果API与网页不同源,需要后端配置CORS


三、改进

如果我们要进行多次前后端联调,那上面这段代码不是有点麻烦吗,有没有更优雅一点代码呢,当然有,看下面代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">新歌速递</button>
    <ul id="ul">

    </ul>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script>
        const btn = document.getElementById('btn');
        btn.addEventListener('click', () => { 

            $.ajax({
                url: 'https://api.example.com/top/songs?type=7',
                method: 'GET',
                dataType: 'json',
                success: function (res) {
                    console.log(res);
                    // 然后完成接下来的逻辑
                }
            })


        })
    </script>


</body>

</html>

这两段代码的主要区别在于实现AJAX请求的方式不同:现在使用jQuery的$.ajax()方法,前面那段使用原生JavaScript的XMLHttpRequest对象。以下是第一段代码的优势分析:

1. 代码简洁性和可读性

  • jQuery版本 :代码更加简洁,只需要配置一个对象参数即可完成请求,逻辑清晰。

    javascript 复制代码
    $.ajax({
        url: '...',
        method: 'GET',
        dataType: 'json',
        success: function(res) { ... }
    });
  • 原生版本 :需要手动创建XMLHttpRequest对象,处理readyStatestatus,代码量更多,逻辑分散。

    javascript 复制代码
    let xhr = new XMLHttpRequest();
    xhr.open('GET', '...', true);
    xhr.onreadystatechange = () => { ... };
    xhr.send();

2. 自动处理JSON解析

  • jQuery版本 :通过设置dataType: 'json',jQuery会自动将响应数据解析为JSON对象,无需手动调用JSON.parse()
  • 原生版本 :需要手动调用JSON.parse(xhr.responseText)解析响应数据。

3. 跨浏览器兼容性

  • jQuery版本:jQuery内部处理了不同浏览器的兼容性问题(如早期的IE),开发者无需关心底层差异。
  • 原生版本 :可能需要额外代码处理不同浏览器的兼容性(如ActiveXObject)。

4. 错误处理

  • jQuery版本 :可以通过errorfail回调统一处理错误,例如:

    javascript 复制代码
    $.ajax({
        ...
        error: function(xhr, status, error) { ... }
    });
  • 原生版本 :需要在onreadystatechange中检查xhr.status,错误处理逻辑分散。

5. 链式调用和扩展性

  • jQuery版本 :支持Promise风格的链式调用(如.done(), .fail()),便于扩展和维护。

    javascript 复制代码
    $.ajax({...}).done(function(res) {...}).fail(function() {...});
  • 原生版本:需要自行封装Promise或使用回调函数,扩展性较差。

6. 其他功能

  • jQuery版本 :支持更高级的功能(如请求超时、全局事件、请求取消等),只需配置参数即可。

    javascript 复制代码
    $.ajax({
        timeout: 5000, // 超时设置
        beforeSend: function() { ... } // 发送前回调
    });
  • 原生版本:需要手动实现这些功能。

原生版本的优势

虽然jQuery版本更简洁,但原生版本也有其优势:

  1. 无依赖:不依赖第三方库,减少页面加载资源。
  2. 性能:直接使用浏览器API,理论上性能更高(但差异通常很小)。
  3. 学习价值:理解原生实现有助于掌握底层原理。

那还能改进吗,当然,再看接下来的代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">新歌速递</button>
    <ul id="ul">

    </ul>

    <script>
        const btn = document.getElementById('btn');
        btn.addEventListener('click', () => { 
           fetch('http://192.168.31.45:3000/top/song?type=7')
           .then(data => data.json())
           .then(res => {
            console.log(res);
           })
           
            
        })
    </script>


</body>

</html>

这段代码使用了现代JavaScript的 fetch API 来实现AJAX请求,相比之前的 jQuery $.ajax()原生 XMLHttpRequest,它有以下优势和不同之处:


1. fetch API 的优势

更现代、更简洁
  • fetch 是ES6引入的现代API,语法更简洁,基于 Promise,避免了回调地狱(Callback Hell)。
  • 相比XMLHttpRequest,代码量更少;相比$.ajax(),它是原生API,无需引入jQuery。
Promise 链式调用
  • fetch 返回一个 Promise ,可以使用 .then().catch() 进行链式调用,逻辑更清晰。
  • XMLHttpRequest 使用回调函数,$.ajax() 虽然支持Promise,但fetch是原生支持。
更灵活的请求和响应处理
  • fetch 的响应是一个 Response 对象 ,可以方便地读取JSON、文本、Blob等格式:

    js 复制代码
    fetch(url)
      .then(response => response.json()) // 解析JSON
      .then(data => console.log(data))
      .catch(error => console.error(error));
  • XMLHttpRequest 需要手动解析 xhr.responseText,而 fetch 提供了 .json(), .text(), .blob() 等方法。

默认不携带Cookie,更安全
  • fetch 默认不会发送或接收Cookies(除非设置 credentials: 'include'),安全性更高。
  • XMLHttpRequest$.ajax() 默认行为可能不同,需要额外配置。

2. 对比之前的方案

特性 fetch API $.ajax() (jQuery) XMLHttpRequest
语法简洁性 ⭐⭐⭐(Promise风格) ⭐⭐(配置对象) ⭐(回调方式)
是否需要库 ❌ 原生支持 ✅ 依赖jQuery ❌ 原生支持
Promise支持 ✅ 原生支持 ✅(jQuery 3.0+) ❌(需手动封装)
JSON解析 response.json() 自动(dataType: 'json' 手动JSON.parse()
错误处理 .catch() .fail()error回调 手动检查xhr.status
跨域请求控制 credentials: 'include' xhr.withCredentials = true xhr.withCredentials = true
浏览器兼容性 现代浏览器(IE不支持) 广泛支持(包括旧版IE) 广泛支持

3. fetch 的潜在缺点

不直接支持超时(需手动封装)

fetch 本身没有超时参数,但可以用 Promise.race() 实现:

js 复制代码
const timeout = new Promise((_, reject) => 
  setTimeout(() => reject(new Error("请求超时")), 5000)
);

Promise.race([fetch(url), timeout])
  .then(response => response.json())
  .catch(error => console.error(error));

$.ajax()XMLHttpRequest 可以直接设置 timeout

默认不处理HTTP错误状态

fetch 只有在 网络错误 (如CORS、DNS失败)时才会 reject,而 HTTP 404/500 仍然会进入 .then(),需要手动检查:

js 复制代码
fetch(url)
  .then(response => {
    if (!response.ok) throw new Error("HTTP错误: " + response.status);
    return response.json();
  })
  .catch(error => console.error(error));

$.ajax()XMLHttpRequest 可以自动处理HTTP错误。

IE完全不支持

如果需要兼容IE,必须使用 XMLHttpRequest$.ajax()


4. 代码改进建议

如果想更健壮地使用 fetch,可以这样写:

js 复制代码
btn.addEventListener('click', async () => { 
  try {
    const response = await fetch('http://192.168.31.45:3000/top/song?type=7');
    if (!response.ok) throw new Error("请求失败: " + response.status);
    const res = await response.json();
    console.log(res);
    // 渲染歌曲列表
    res.data.forEach(song => {
      const li = document.createElement('li');
      li.textContent = song.name;
      document.getElementById('ul').appendChild(li);
    });
  } catch (error) {
    console.error("请求出错:", error);
  }
});
  • 使用 async/await 让代码更易读。
  • 检查 response.ok 确保HTTP请求成功。
  • 错误处理更完善。

总结

方案 适用场景
fetch 现代浏览器、简洁Promise风格、无需jQuery
$.ajax() 需要兼容旧浏览器、习惯jQuery、需要高级功能(如自动重试)
XMLHttpRequest 需要最大兼容性(如IE)、无依赖、学习底层原理

推荐选择:

  • 现代项目优先用 fetch(代码更简洁,未来趋势)。
  • 旧项目或需要兼容IE用 $.ajax()XMLHttpRequest
  • 如果已经用了jQuery,$.ajax() 仍然是不错的选择
相关推荐
浦东大花菜1 分钟前
Rust-代码组织(package crate module)
前端·后端·rust
丸卜6 分钟前
web复习(一)
前端
前端筱园20 分钟前
重新认识被低估的script标签,小标签如何成就大作为
前端
wjykp37 分钟前
day5 cpp:,对象的组织(const对象),
开发语言·前端·javascript
心.c41 分钟前
深入了解Vue2和Vue3的响应式原理
前端·javascript·vue.js
又逢乱世1 小时前
刚出炉热乎的。UniApp X 封装 uni.request
前端·uni-app
struggle20252 小时前
VoltAgent 是一个开源 TypeScript 框架,用于构建和编排 AI 代理
javascript·css·人工智能·typescript·开源
树懒的梦想2 小时前
10 个免费虚拟手机号网站|保护隐私|拒绝垃圾短信
前端
普通老人2 小时前
【前端】html2pdf实现用前端下载pdf
前端·pdf
小小小小宇2 小时前
自定义 ESLint 插件:禁止直接发起 fetch 或 axios 请求
前端