首页
/ create-react-app 中用 AJAX 请求获取数据:fetch、Promise 与 react-app-polyfill 浏览器兼容方案

create-react-app 中用 AJAX 请求获取数据:fetch、Promise 与 react-app-polyfill 浏览器兼容方案

2026-09-04 17:40:36作者:裴麒琰

React 本身并不规定具体的数据获取方式,create-react-app 生成的项目在实践中通常使用 axios 这类第三方库,或浏览器内置的 fetch() API 来发起 AJAX 请求。读完本文,你将掌握 fetch() 与 Promise、async / await 的标准用法,并了解在 create-react-app 项目中为旧浏览器(尤其是 Internet Explorer)补齐运行时能力的完整方案——即仓库内置的 react-app-polyfill 包的四个入口点及其源码实现。

两种主流的数据获取方式

React 不预设数据获取方案,社区常见的选择有两种:

  1. axios 等第三方库:在 package.json 中安装依赖后在组件中 import 使用,API 更贴近 XMLHttpRequest,内置了请求/响应拦截器、自动 JSON 转换等能力;
  2. 浏览器原生 fetch() API:无需安装任何依赖,由全局 fetch 函数直接发起请求。

无论选择哪种方式,二者的底层都依赖 Promise 机制。

fetch() API:返回 Promise 的请求机制

全局 fetch 函数接收一个 URL 作为输入,返回一个 Promise,该 Promise 最终解析为一个 Response 对象。基本用法如下:

// 发起 GET 请求
fetch('https://api.example.com/items')
  .then((response) => {
    // Response 对象需要先转换为 JSON
    return response.json();
  })
  .then((data) => {
    // 这里拿到解析后的数据
    console.log(data);
  })
  .catch((error) => {
    console.error('请求失败', error);
  });

需要特别注意的是,Response 对象本身只是 HTTP 响应(包含 statusheaders 等元信息),业务数据还需要通过 response.json() 等方法进一步解析。由于 fetch 返回的 Promise 只在网络层失败(如断网、DNS 解析失败)时 reject,HTTP 4xx/5xx 状态码并不会自动进入 catch 分支,通常需要自行检查 response.ok

fetch('/api/notes')
  .then((response) => {
    if (!response.ok) {
      throw new Error(`HTTP 错误状态:${response.status}`);
    }
    return response.json();
  })
  .then((notes) => {
    console.log(notes);
  });

用 async / await 简化异步逻辑

Promise 是异步操作的最终结果的抽象。axios 与 fetch() 底层都使用 Promise,而 async / await 语法可以进一步减少回调嵌套,使异步代码更接近同步写法:

async function loadUser() {
  try {
    const response = await fetch('/api/user/1');
    if (!response.ok) {
      throw new Error(`HTTP 错误状态:${response.status}`);
    }
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('请求失败', error);
  }
}

从 create-react-app 的 kitchensink 集成测试中也能看到这一点:async / await 是被项目作为一等公民支持的语法特性,对应测试文件为 AsyncAwait.js 及其测试用例 AsyncAwait.test.js,说明该语法在构建管线(Babel 转译)层面是被完整支持的。

关键前提:目标浏览器必须支持 fetch 和 Promise

在使用上述 API 前,必须确认目标受众的浏览器环境中 fetch() API 和 Promise 是可用的。对于现代浏览器,二者均已原生支持;但对于 Internet Explorer 等旧浏览器,则必须手动引入 polyfill。create-react-app 针对这一场景提供了仓库内置的 react-app-polyfill 包,这一点在官方浏览器支持文档 supported-browsers-features.md 中也有明确说明:默认生成的项目只支持所有现代浏览器,IE 9/10/11 支持需要额外引入 polyfill,且项目默认不包含任何 polyfill

这一点可以直接从模板源码得到印证:默认 JS 模板的入口文件 index.js 中没有任何 polyfill 导入,第一行就是 import React from 'react';TypeScript 模板的 index.tsx 同样如此。

react-app-polyfill 的四个入口点

react-app-polyfill 包(见 package.json)提供四个面向不同目标的入口文件,这也是 files 字段中声明的全部产物:

入口 适用场景 提供的能力
react-app-polyfill/ie11 支持 IE 11 Promise、window.fetch、Object.assign、Symbol、Array.from
react-app-polyfill/ie9 支持 IE 9(自动覆盖 IE 10/11) 在 ie11 基础上追加 Map、Set、requestAnimationFrame
react-app-polyfill/stable 补齐目标浏览器缺失的稳定语言特性 core-js/stable 全套稳定 polyfill + regenerator-runtime
react-app-polyfill/jsdom 测试环境(Jest 的 jsdom) 仅 fetch polyfill

使用前先安装:

npm install react-app-polyfill

或:

yarn add react-app-polyfill

如果只需要支持 IE 11,在 src/index.js第一行导入:

// This must be the first line in src/index.js
import 'react-app-polyfill/ie11';

// ...

如果需要支持 IE 9,则改为:

// This must be the first line in src/index.js
import 'react-app-polyfill/ie9';

// ...

由于 ie9 入口内部会先 require('./ie11')(见 ie9.js 第 9 行),所以导入 ie9 会自动包含 ie11 的全部能力。

源码解析:ie11 入口补齐了哪些能力

阅读 ie11.js 的实现,可以看到它对 CRA 项目运行所必需的五个语言特性逐项补齐:

if (typeof Promise === 'undefined') {
  // Rejection tracking prevents a common issue where React gets into an
  // inconsistent state due to an error, but it gets swallowed by a Promise,
  // and the user has no idea what causes React's erratic future behavior.
  require('promise/lib/rejection-tracking').enable();
  self.Promise = require('promise/lib/es6-extensions.js');
}

这里有两个值得注意的细节:

  1. 按需替换:只有当原生 Promise 不存在时才挂载 polyfill,避免覆盖浏览器原生实现;
  2. 开启 rejection tracking:注释明确说明,这是为了防止 Promise 吞掉错误导致 React 陷入不一致状态——被吞掉的 rejection 会让用户无法解释 React 后续的异常行为。对于数据获取场景,这意味着在 IE 环境下未处理的 fetch().catch() 丢失仍然能通过全局机制被追踪到。
// Make sure we're in a Browser-like environment before importing polyfills
// This prevents `fetch()` from being imported in a Node test environment
if (typeof window !== 'undefined') {
  // fetch() polyfill for making API calls.
  require('whatwg-fetch');
}

typeof window !== 'undefined' 这层守卫是一个关键设计:防止在 Node 测试环境(Jest)中引入 whatwg-fetch。Jest 默认运行在 jsdom 环境,若不加守卫,fetch polyfill 会污染 Node 全局对象。仓库变更历史中也有对应的修复记录("Don't polyfill fetch for Node"),说明这是真实踩坑后沉淀下来的防御逻辑。

其余部分则补齐数据获取和组件开发中高频使用的特性:

  • Object.assign = require('object-assign') —— React 开发中常用(也是 Object Spread 语法 { ...a, ...b } 转译后的运行时依赖);
  • core-js/features/symbol —— 支撑 for...of 等依赖 Symbol 的语法;
  • core-js/features/array/from —— 支撑数组展开 [...arr] 以及可迭代对象展开(...Set...Map)。

ie9.js 在此之上追加了 core-js/features/mapcore-js/features/set 以及 raf(requestAnimationFrame polyfill),源码注释说明这些是 React 16+ 的运行时依赖。

stable 入口:结合 browserslist 补齐其余稳定特性

除了 IE 场景,stable 入口可以补齐目标浏览器缺失的其他稳定语言特性。其实现 stable.js 非常简洁:

// Polyfill stable language features.
// It's recommended to use @babel/preset-env and browserslist
// to only include the polyfills necessary for the target browsers.
require('core-js/stable');
require('regenerator-runtime/runtime');

源码注释指出推荐配合 Babel 的 @babel/preset-envbrowserslist 配置,只为目标浏览器包含真正需要的 polyfill——在 create-react-app 中使用 stable 入口时,构建管线会自动依据项目 package.json 中定义的 browserslist 做按需裁剪。regenerator-runtime 则是 async / await 和 Generator 转译后的运行时支撑,这也是为什么数据获取代码使用 async / await 时,在旧浏览器上同样依赖 polyfill 的原因。

如果同时需要支持 IE 9/11 和更广泛的稳定特性,按官方说明应同时导入两个入口:

// For IE9:
import 'react-app-polyfill/ie9';
import 'react-app-polyfill/stable';

// For IE11:
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';

测试环境:jsdom 入口

react-app-polyfill 还提供 jsdom.js 入口,其全部内容就是带 window 守卫的 whatwg-fetch 引入。它专为 Jest 的 jsdom 测试环境设计:如果组件测试中需要断言 fetch 调用或模拟网络响应,可以导入该入口让 fetch 在 jsdom 中可用(生产代码通常直接 mock fetch 即可,无需引入 polyfill)。

polyfill 依赖一览

package.json 可以看到各入口背后的实际依赖及其版本约束:

依赖 版本约束 对应能力
promise ^8.1.0 IE 环境的 Promise 实现
whatwg-fetch ^3.6.2 window.fetch 的 WHATWG 标准实现
object-assign ^4.1.1 Object.assign
core-js ^3.19.2 Symbol、Array.from、Map、Set 等语言特性
raf ^3.4.1 requestAnimationFrame(仅 ie9 入口)
regenerator-runtime ^0.13.9 async/await 与 Generator 运行时(仅 stable 入口)

实践建议

  1. 默认面向现代浏览器:create-react-app 生成的项目默认不内置任何 polyfill,fetch 与 Promise 在现代浏览器中开箱即用,优先使用原生 fetch() + async / await 的写法,避免不必要的包体积开销;
  2. 需要兼容 IE 时再引入:在 src/index.js 第一行导入 react-app-polyfill/ie11(或 ie9),并视需要追加 stable 入口;导入顺序必须是第一行,保证 polyfill 在任何业务模块执行前生效;
  3. 注意错误处理差异fetch 不会对 HTTP 错误状态码 reject,response.ok 检查要写进业务代码;而在 IE polyfill 环境下,未捕获的 Promise rejection 会因 rejection tracking 被暴露出来,这是排查"React 状态异常"问题的重要线索;
  4. 测试环境隔离:Node/Jest 环境中不要手动引入 IE 类 polyfill,react-app-polyfillwindow 守卫已自动避免这一风险。

对于如何在 React 组件中组织数据获取逻辑(加载状态、错误状态、请求时机等),React 官方文档中有专门的 AJAX FAQ 条目可供参考。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384