
react native 应用在 wi-fi 或移动数据断开时因未捕获 fetch 异常而崩溃,本文详解如何通过 promise 链式错误处理与 async/await 安全模式避免崩溃,并附最佳实践代码示例。
react native 应用在 wi-fi 或移动数据断开时因未捕获 fetch 异常而崩溃,本文详解如何通过 promise 链式错误处理与 async/await 安全模式避免崩溃,并附最佳实践代码示例。
在 React Native 中,fetch 是基于 Promise 的异步网络请求方法,其本质不具备自动重试或离线降级能力。当设备处于无网络状态(如关闭 Wi-Fi 且未开启蜂窝数据)时,fetch 会立即 reject 并抛出 TypeError: Network request failed 错误。若该异常未被显式捕获,将导致 JavaScript 层未处理拒绝(unhandled rejection),进而触发应用崩溃——尤其在 Android 上,未捕获的 Promise rejection 可能被 OkHttp 底层透传为致命异常。
✅ 正确处理 fetch 异常的两种方式
方式一:Promise 链式 .catch()(推荐用于简单场景)
const loadMovies = () => {
fetch('https://reactnative.dev/movies.json')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(json => {
console.log('Movies loaded:', json);
setMovies(json.movies || []);
})
.catch(error => {
console.warn('Network request failed:', error.message);
// ✅ 关键:此处必须提供降级逻辑,例如显示空状态、缓存数据或 Toast 提示
Alert.alert('网络不可用', '请检查您的网络连接后重试');
setMovies([]); // 避免后续渲染依赖未定义数据
});
};方式二:async/await + try/catch(更易读、支持同步风格控制流)
const loadMovies = async () => {
try {
const response = await fetch('https://reactnative.dev/movies.json', {
headers: { 'Cache-Control': 'no-cache' },
// ⚠️ 注意:timeout 需自行封装(fetch 原生不支持),见下方提示
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const json = await response.json();
setMovies(json.movies || []);
} catch (error) {
console.error('[Network Error]', error);
// ✅ 统一错误分类处理
if (error.name === 'TypeError' && error.message.includes('Network request failed')) {
Alert.alert('离线提示', '当前无网络连接,请稍后重试');
} else {
Alert.alert('加载失败', '服务暂时不可用');
}
setMovies([]);
}
};⚠️ 关键注意事项
不要假设网络始终可用:即使已配置 android.permission.INTERNET 和 android.permission.ACCESS_NETWORK_STATE,仍需在业务逻辑中主动防御性编程;
避免“悬空”依赖:切勿在 .then() 后直接执行依赖响应数据的同步代码(如 doSomethingWith(data)),而未包裹在 Promise 链内——这会导致 data 为 undefined 引发后续错误;
-
超时控制需手动实现:fetch 原生不支持 timeout,建议使用 AbortController:
const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch(url, { signal: controller.signal }); clearTimeout(timeoutId); // ... 处理响应 } catch (error) { if (error.name === 'AbortError') { console.warn('Request timed out'); } throw error; } OkHttp BOM 版本非根本解:你添加的 okhttp-bom:4.7.2 仅统一依赖版本,无法规避未捕获异常;崩溃根源始终是 JS 层错误处理缺失。
✅ 最佳实践总结
- 每个 fetch 必须配对 .catch() 或 try/catch;
- 在 catch 块中提供明确的 UI 反馈与状态回退(如清空列表、显示离线占位图);
- 对 response.ok 进行二次校验,区分网络层失败(如 DNS 错误)与业务层失败(如 404/500);
-
结合 NetInfo 库(@react-native-community/netinfo)预判网络状态,提升用户体验:
npx react-native add @react-native-community/netinfo
import NetInfo from '@react-native-community/netinfo'; const isOnline = await NetInfo.fetch().then(state => state.isConnected); if (!isOnline) return Alert.alert('请连接网络');
通过以上结构化错误处理,你的 React Native 应用将具备真正的离线韧性——不再因一次失败的 fetch 而崩溃,而是优雅降级、稳定运行。










