fetch和ajax区别

9 分钟
50 阅读
fetch和ajax区别

fetchAJAX 都是用于浏览器与服务器通信的技术,但它们在设计理念、使用方式和功能特性上有显著区别。以下是两者的详细对比:


1. 核心概念

特性 Fetch API AJAX(XMLHttpRequest)
技术本质 现代浏览器原生 API(基于 Promise) 早期的浏览器 API(基于事件回调)
语法风格 Promise 链式调用,更简洁 事件监听 + 回调函数,代码冗长
诞生时间 ES6(2015年)引入 1999年由微软提出,2006年标准化

2. 代码对比

AJAX(XMLHttpRequest)

javascript 复制代码
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText));
  } else {
    console.error('请求失败');
  }
};
xhr.onerror = function() {
  console.error('网络错误');
};
xhr.send();
  • 缺点
    • 回调嵌套复杂(“回调地狱”)。
    • 需手动处理响应状态码和错误。

Fetch API

javascript 复制代码
fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) throw new Error('请求失败');
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error(error));
  • 优点
    • 链式调用,逻辑清晰。
    • 默认返回 Promise,支持 async/await

3. 关键功能差异

功能 Fetch AJAX
请求取消 通过 AbortController 实现 原生支持 xhr.abort()
超时控制 需手动封装 Promise.race 原生支持 xhr.timeout
响应类型 需调用 .json()/.text() 等方法 通过 xhr.responseType 直接设置
Cookie 发送 默认不携带,需设置 credentials: 'include' 默认携带
进度监控 不支持 支持 xhr.upload.onprogress

4. 实际应用场景

优先使用 Fetch 的情况

  • 现代前端项目
    javascript 复制代码
    // 结合 async/await 更简洁
    async function loadData() {
      try {
        const res = await fetch('/api/data');
        const data = await res.json();
        console.log(data);
      } catch (error) {
        console.error(error);
      }
    }
  • 需要流式数据处理
    javascript 复制代码
    const response = await fetch('/large-file');
    const reader = response.body.getReader();
    // 逐块读取数据

仍需使用 AJAX 的情况

  • 兼容旧浏览器(如 IE11):
    javascript 复制代码
    if (typeof fetch === 'undefined') {
      // 回退到 AJAX
    }
  • 需要上传进度监控
    javascript 复制代码
    xhr.upload.onprogress = (e) => {
      const percent = (e.loaded / e.total) * 100;
      console.log(`上传进度: ${percent}%`);
    };

5. 补充说明

  • jQuery 的 $.ajax
    封装了 XMLHttpRequest,提供更简单的语法,但仍基于回调:
    javascript 复制代码
    $.ajax({
      url: '/api/data',
      method: 'GET',
      success: (data) => console.log(data),
      error: (err) => console.error(err)
    });
  • Axios
    基于 Promise 的第三方库,兼容浏览器和 Node.js,综合了 Fetch 和 AJAX 的优点
    javascript 复制代码
    axios.get('/api/data')
      .then(response => console.log(response.data))
      .catch(error => console.error(error));

总结

维度 Winner 原因
代码简洁性 Fetch Promise 链式调用比回调更直观
功能完整性 AJAX 原生支持取消、超时、进度监控等特性
现代开发 Fetch/Axios 原生或第三方库对 Promise 和 TypeScript 支持更好

建议

  • 新项目优先使用 Fetch APIAxios
  • 旧项目维护或需要特定功能(如上传进度)时选择 AJAX

对于监听网络传输(如监控请求/响应进度、流量分析或调试),fetchAJAX 的能力差异显著。以下是具体对比和解决方案:


1. 进度监控能力对比

功能 Fetch API AJAX (XMLHttpRequest)
下载进度 ❌ 原生不支持 ✅ 通过 xhr.onprogress 监听
上传进度 ❌ 原生不支持 ✅ 通过 xhr.upload.onprogress
实时中断请求 ✅ 通过 AbortController ✅ 原生 xhr.abort()
分块数据流处理 ✅ 支持 response.body.getReader() ❌ 仅能获取完整响应

2. 监听网络传输的具体实现

(1)AJAX 的完整进度监控

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

// 上传进度监听
xhr.upload.onprogress = (e) => {
  const uploadPercent = Math.round((e.loaded / e.total) * 100);
  console.log(`上传进度: ${uploadPercent}%`);
};

// 下载进度监听
xhr.onprogress = (e) => {
  const downloadPercent = Math.round((e.loaded / e.total) * 100);
  console.log(`下载进度: ${downloadPercent}%`);
};

xhr.open('POST', '/api/upload');
xhr.send(formData);

优势

  • 原生支持上传/下载进度监控,适合大文件传输场景。

(2)Fetch API 的变通方案

虽然原生 fetch 不支持进度事件,但可通过以下方式实现类似功能:

方案1:分块读取响应流(仅下载)
javascript 复制代码
const response = await fetch('/api/large-file');
const reader = response.body.getReader();
let receivedLength = 0;
const totalLength = +response.headers.get('Content-Length');

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  receivedLength += value.length;
  console.log(`下载进度: ${Math.round((receivedLength / totalLength) * 100)}%`);
}
方案2:自定义包装器(上传进度需借助中间层)
javascript 复制代码
async function fetchWithProgress(url, options) {
  const { onUploadProgress, ...fetchOptions } = options;
  
  // 如果是 FormData 上传,需手动计算进度(非精确)
  if (onUploadProgress && fetchOptions.body instanceof FormData) {
    const totalSize = [...fetchOptions.body].reduce((acc, [k, v]) => 
      acc + (v instanceof File ? v.size : String(v).length), 0);
    let uploaded = 0;
    
    // 劫持 body 的流式写入
    const originalBody = fetchOptions.body;
    const trackedStream = new ReadableStream({
      start(controller) {
        const reader = originalBody.stream().getReader();
        async function push() {
          const { done, value } = await reader.read();
          if (done) {
            controller.close();
            return;
          }
          uploaded += value.length;
          onUploadProgress({ loaded: uploaded, total: totalSize });
          controller.enqueue(value);
          push();
        }
        push();
      }
    });
    fetchOptions.body = trackedStream;
  }

  return fetch(url, fetchOptions);
}

// 使用示例
fetchWithProgress('/api/upload', {
  method: 'POST',
  body: formData,
  onUploadProgress: (e) => {
    console.log(`上传进度: ${Math.round((e.loaded / e.total) * 100)}%`);
  }
});

局限性

  • 上传进度监控需要手动劫持数据流,且对非 FormData 类型支持有限。

3. 高级网络分析工具

(1)浏览器开发者工具

  • Network 面板:直接查看所有请求的耗时、流量大小和瀑布图。
  • Performance 面板:分析网络请求对页面性能的影响。

(2)第三方库

  • Axios:封装了上传/下载进度监听:
    javascript 复制代码
    axios.post('/api/upload', formData, {
      onUploadProgress: (progressEvent) => {
        const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
        console.log(`上传进度: ${percent}%`);
      }
    });
  • Pako:用于监控压缩流量(如 Gzip 数据流)。

(3)Service Worker 拦截

通过 Service Worker 监听所有 fetch 请求,实现流量统计或缓存控制:

javascript 复制代码
// service-worker.js
self.addEventListener('fetch', (event) => {
  console.log(`拦截请求: ${event.request.url}`);
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

4. 适用场景推荐

需求 推荐方案
精确的上传/下载进度监控 AJAX(xhr.upload.onprogress
流式数据处理 Fetch API(response.body.getReader()
兼容旧浏览器 AJAX 或 Axios
全局网络拦截/分析 Service Worker + Fetch 监听

总结

  • AJAX 是进度监控的“原生王者”,适合文件上传等场景。
  • Fetch API 更现代且支持流式处理,但需额外代码实现进度监听。
  • 终极方案:优先使用 fetch + AbortController(中断请求)和 ReadableStream(流处理),必要时用 Axios 或降级到 AJAX。

评论

评论

发表评论