Node.js v20 引入 fetch API 后异步请求性能比 axios 快多少?

文章导读
Node.js v20 原生 fetch API 基于 undici 实现,去除了第三方库的中间封装层,因此在纯 HTTP 请求吞吐量上通常优于 axios。但具体性能差距取决于并发量、Payload 大小及业务逻辑复杂度,不能一概而论。axios 在拦截器、自动转换等开发体验功能上仍具有优势。
📋 目录
  1. A 性能差异核心原因
  2. B 专业基准测试脚本
  3. C 内存与资源监控
  4. D 迁移常见坑与排查
  5. E 选型决策建议
  6. F 参考来源
A A

Node.js v20 原生 fetch API 基于 undici 实现,去除了第三方库的中间封装层,因此在纯 HTTP 请求吞吐量上通常优于 axios。但具体性能差距取决于并发量、Payload 大小及业务逻辑复杂度,不能一概而论。axios 在拦截器、自动转换等开发体验功能上仍具有优势。

先说结论:在高并发、轻量级请求场景下,原生 fetch 性能更优;在需要复杂请求配置、拦截器及旧版本兼容的场景下,axios 仍是首选。

  • 性能差异:原生 fetch 底层直接调用 undici,减少了实例化开销,QPS 通常更高
  • 核心风险:fetch 不会自动 reject HTTP 错误状态(如 404/500),需手动处理
  • 迁移建议:核心链路建议先进行基准测试,非核心链路(如日志上报)可优先迁移

性能差异核心原因

Node.js v18+ 引入的全局 fetch API 底层基于 undici 库,这是 Node.js 官方维护的 HTTP 客户端,与运行时集成度更高。axios 作为第三方库,为了兼容浏览器 XMLHttpRequest 及提供便捷功能,引入了额外的 Promise 封装和数据处理逻辑。

Node.js v20 引入 fetch API 后异步请求性能比 axios 快多少?

在纯网络 I/O 场景下,fetch 减少了对象创建和原型链查找的开销。但在复杂业务场景中,axios 的自动 JSON 转换和请求拦截器能显著减少样板代码,此时开发效率的提升可能比微小的性能增益更重要。

专业基准测试脚本

单次 Date.now() 测量受网络波动影响极大,不具备统计学意义。建议使用 node:perf_hooks 进行多次迭代测试,并包含预热环节。以下脚本可在本地运行以获取准确数据:

Node.js v20 引入 fetch API 后异步请求性能比 axios 快多少?
const { performance } = require('perf_hooks');
const axios = require('axios');

const URL = 'https://api.example.com/data';
const ITERATIONS = 100;

async function benchmarkFetch() {
  // 预热
  for (let i = 0; i < 10; i++) await fetch(URL);
  
  const start = performance.now();
  for (let i = 0; i < ITERATIONS; i++) {
    const res = await fetch(URL);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    await res.text();
  }
  const end = performance.now();
  return (end - start) / ITERATIONS;
}

async function benchmarkAxios() {
  // 预热
  for (let i = 0; i < 10; i++) await axios.get(URL);
  
  const start = performance.now();
  for (let i = 0; i < ITERATIONS; i++) {
    await axios.get(URL);
  }
  const end = performance.now();
  return (end - start) / ITERATIONS;
}

(async () => {
  try {
    const fetchAvg = await benchmarkFetch();
    const axiosAvg = await benchmarkAxios();
    console.log(`Fetch Avg: ${fetchAvg.toFixed(2)}ms`);
    console.log(`Axios Avg: ${axiosAvg.toFixed(2)}ms`);
  } catch (e) {
    console.error('Benchmark failed:', e.message);
  }
})();

内存与资源监控

除了响应时间,内存占用也是关键指标。fetch 基于 undici 通常在长连接池管理上更高效。可通过以下方法监控:

Node.js v20 引入 fetch API 后异步请求性能比 axios 快多少?
  1. 代码级监控:在请求前后打印 process.memoryUsage() 观察堆内存变化。
  2. 命令行监控:使用 node `--inspect` 配合 Chrome DevTools 查看内存快照,或使用 clinic.js 进行性能分析。
  3. 关注点:长时间运行后,观察 heapUsed 是否持续增长,排查是否存在连接未关闭导致的内存泄漏。

迁移常见坑与排查

从 axios 迁移到 fetch 时,以下技术细节极易导致线上故障,需重点排查:

  • 错误处理机制:fetch 仅在网路错误时 reject,HTTP 状态码 4xx/5xx 不会抛出异常。
    修正:必须手动检查 if (!response.ok) throw new Error(...)
  • 超时控制:fetch 原生无 timeout 选项。
    修正:需使用 AbortController 配合 setTimeout 实现取消请求。
  • Cookie 携带:fetch 默认不发送 Cookie。
    修正:需显式设置 credentials: 'include'(跨域场景)。
  • 请求体序列化:fetch 发送 JSON 需手动 JSON.stringify 并设置 Content-Type
    修正:封装统一请求函数处理 headers 和 body。

选型决策建议

根据实际场景选择 HTTP 客户端:

  • 选择 fetch:Node.js v18+ 环境、微服务内部调用、对包体积敏感、追求极致性能的内部工具。
  • 选择 axios:需要支持浏览器旧版本、重度依赖拦截器(如统一鉴权)、需要自动转换 JSON 表单的复杂业务系统。
  • 折中方案:使用 ofetchky 等基于 fetch 封装的库,既保留性能优势又补充了易用性功能。

参考来源

  • Node.js Official Docs: Fetch API
  • GitHub: nodejs/undici
  • GitHub: axios/axios
  • Node.js Performance Best Practices