
本文详解 react native 应用在无 wi-fi/移动网络时因未妥善捕获 fetch 异常而崩溃的问题,提供 promise 链与 async/await 两种健壮处理模式,并附关键代码示例与最佳实践。
本文详解 react native 应用在无 wi-fi/移动网络时因未妥善捕获 fetch 异常而崩溃的问题,提供 promise 链与 async/await 两种健壮处理模式,并附关键代码示例与最佳实践。
在 React Native 中,fetch 是异步网络请求的核心 API,但其本质是基于 Promise 的,不会自动阻止后续代码执行,也不会静默吞掉错误。当设备处于离线状态(Wi-Fi 和蜂窝数据均关闭)时,fetch 会立即 reject 并抛出 TypeError: Network request failed —— 若未显式 .catch() 或 try/catch 捕获,该未处理的 Promise rejection 将触发 JavaScript 运行时错误,最终导致应用在 Android/iOS 上意外崩溃(尤其在生产环境或启用了严格错误策略时)。
这与是否配置 AndroidManifest 权限(如 INTERNET、ACCESS_NETWORK_STATE)或引入 OkHttp BOM 无关:权限仅影响系统级网络访问授权,OkHttp 依赖则优化底层连接复用与日志,二者均无法替代应用层的错误处理逻辑。
✅ 正确处理方式一:Promise 链式写法(推荐用于简单场景)
const loadMovies = () => {
fetch('https://reactnative.dev/movies.json')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(json => {
// ✅ 安全:仅在此处使用成功响应数据
setMovies(json.movies);
setLoading(false);
})
.catch(error => {
// ? 必须捕获:涵盖网络失败、解析错误、HTTP 状态码异常等
console.warn('Network request failed:', error.message);
setErrorMessage('无法连接到服务器,请检查网络后重试');
setLoading(false);
});
};⚠️ 注意:.catch() 会捕获链中任意环节抛出的异常(包括 response.json() 解析失败),因此它是统一的错误出口。
✅ 正确处理方式二:async/await + try/catch(推荐用于复杂逻辑或需同步语义)
const loadMovies = async () => {
try {
const response = await fetch('https://reactnative.dev/movies.json');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const json = await response.json(); // ✅ await 确保 JSON 解析完成后再继续
setMovies(json.movies);
} catch (error) {
// ? 捕获所有可能异常:网络中断、DNS 失败、超时、JSON 格式错误、HTTP 错误码等
console.error('Fetch failed:', error);
setErrorMessage(
error.name === 'TypeError' && error.message.includes('Network request failed')
? '当前无网络连接'
: '数据加载失败,请稍后重试'
);
} finally {
setLoading(false);
}
};? 常见反模式(务必避免)
- ❌ 忘记 .catch() 或 try/catch,导致 Promise rejection 未被处理;
- ❌ 在 .then() 中直接操作未定义的 json.data 而不校验响应结构;
- ❌ 将 fetch() 后续逻辑(如 setState)写在 .then() 外部,造成“假同步”依赖;
- ❌ 仅检查 response.status === 200,忽略 response.ok(它覆盖 200–299 范围,更语义化)。
? 补充建议
-
添加超时控制:原生 fetch 不支持 timeout,可借助 AbortController:
const controller = new AbortController(); setTimeout(() => controller.abort(), 10000); // 10秒超时 const response = await fetch(url, { signal: controller.signal }); - 离线优先策略:结合 NetInfo 库预判网络状态,提前降级 UI(如显示缓存数据或离线提示);
- 错误分类处理:区分网络错误(TypeError)、服务端错误(5xx)、客户端错误(4xx),提供差异化用户反馈。
归根结底,健壮的网络层 = 显式错误捕获 + 清晰状态管理 + 用户友好的降级体验。无论网络是否可用,你的应用都应保持可控、可恢复、可感知。










