跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

try/catch/Promise:前端错误处理实战

前端错误处理需区分同步异常与异步场景。try/catch 仅捕获同步代码抛出的异常,无法拦截 setTimeout 或 Promise reject。fetch 请求中 HTTP 状态码如 4xx/5xx 不会触发异常,需手动判断 res.ok。JSON 解析应封装安全函数防止崩溃。业务异常与系统异常需分类处理,前者提示用户,后者上报监控并展示通用提示。

JavaCoder发布于 2026/4/8更新于 2026/5/2518 浏览
try/catch/Promise:前端错误处理实战

try/catch/Promise:前端错误处理实战

前端开发中,错误处理很常见:接口失败、JSON 解析报错、业务失败和系统异常混在一起。不少人要么到处 try/catch,要么该用的地方没用,导致线上问题难排查、用户提示不友好。

用原生 try/catch 配合 Promise/async 的错误处理就能覆盖大部分场景。本文结合真实项目中的常见需求,说明什么时候用 try/catch、什么时候用 .catch()、业务异常和系统异常如何区分,只讲日常开发里 80% 会用到的情况。

一、先搞清楚:try/catch 到底能抓到啥

很多人的第一反应是:try/catch 能把'所有报错'都包住。实际上不是。

1.1 能抓到的:同步代码里的异常

只要错误是在同步代码里抛出的,就会被 catch 捕获。

try {
  const obj = JSON.parse('{ invalid json }'); // 抛出 SyntaxError
  console.log(obj);
} catch (e) {
  console.error('解析失败:', e.message); // 能抓到
}

1.2 抓不到的:异步里的错误

setTimeout 的回调在下一个事件循环执行,执行时 try 早就结束了,所以这里的 catch 完全接不到这个错误。

try {
  setTimeout(() => {
    throw new Error('异步报错'); // 这个 catch 抓不到!
  }, 0);
} catch (e) {
  console.error(e); // 不会执行
}

同理,Promise 内部的 reject、Ajax 的失败回调等异步错误,也不能被外层的 try/catch 直接捕获,需要用别的方式处理。

二、fetch 错误:别只盯着 try/catch

2.1 fetch 是什么?

一句话: fetch 是浏览器自带的、用来向服务器发请求、拿数据的 API。

可以把它理解成:

  • 你:在浏览器里打开页面,想拿到用户列表、商品信息等
  • 服务器:数据放在后端,需要通过「请求」才能给你
  • fetch:就是你发请求、等回复的「工具」

最基础的用法:

// 向 /api/user/list 这个地址发一个「我要数据」的请求
const res = await fetch('/api/user/list');
const data = await res.json(); // 把服务器返回的文本解析成 JSON 对象
console.log(data); // 拿到数据了

几个关键点:

概念大白话解释
fetch(地址)向这个地址发请求,默认是 GET(取数据)
返回值是一个 Promise,所以要用 await 等它完成
res服务器返回的「响应对象」,里面有状态码、响应体等
res.json()把响应体当成 JSON 解析,返回一个 JS 对象
res.text()把响应体当成普通文本,返回字符串

搞懂这些后,下面就能理解为什么 fetch 的错误处理和你想的不太一样了。

2.2 常见误解

有人会这样写:

try {
  const res = await fetch('/api/user/list');
  const data = await res.json();
  return data;
} catch (e) {
  console.error('请求失败', e);
}

这里有个关键点:HTTP 4xx/5xx 并不会让 fetch 抛出异常,只有网络失败、跨域等才会抛。所以:

  • 404、500 等错误 → 不会被 catch 捕获
  • 网络断开、超时 → 会被捕获

2.3 正确做法

要同时处理'网络/请求异常'和'HTTP 状态异常':

async function fetchUserList() {
  try {
    const res = await fetch('/api/user/list');
    if (!res.ok) {
      throw new Error(`HTTP ${res.status}: ${res.statusText}`);
    }
    const data = await res.json();
    return data;
  } catch (e) {
    if (e.name === 'TypeError' && e.message.includes('fetch')) {
      console.error('网络异常,请检查网络');
    } else {
      console.error('请求失败:', e.message);
    }
    throw e; // 让调用方也知道失败了
  }
}

要点:

  • res.ok 判断 2xx,否则手动 throw
  • res.json() 可能抛 JSON 解析错误,会被 catch 捕获
  • 网络类错误在 catch 里单独分支处理

三、JSON 解析错误:最容易漏掉的一类

3.1 常见场景

后端返回的是字符串,或者格式不对:

// 后端返回:"用户不存在"(纯字符串)
// 或者返回:{data: invalid}(非法 JSON)
const data = JSON.parse(response); // 直接崩

JSON.parse 抛的是 SyntaxError,如果不包一层 try/catch,会直接导致整段脚本报错,甚至影响后续逻辑。

3.2 推荐写法

function safeParse(str, fallback = null) {
  try {
    return JSON.parse(str);
  } catch (e) {
    console.warn('JSON 解析失败:', e.message, '原始内容:', str?.slice(0, 50));
    return fallback;
  }
}

const data = safeParse(response, {});

思路:

  • 解析失败时返回一个兜底值(如 {} 或 []),而不是让程序直接崩溃
  • 打 warn 方便排查问题
  • 把解析逻辑封装成 safeParse,减少重复代码

四、业务异常 vs 系统异常:分类处理

很多人把所有错误都当成'失败'来处理,不做区分,交互和排查都会受影响。

4.1 业务异常(可预期的'业务失败')

  • 比如:余额不足、未登录、参数错误、权限不足等
  • 通常由后端通过 HTTP 状态码 + 业务码 + 消息返回
  • 需要展示给用户,并做相应业务流程处理

4.2 系统异常(程序/环境错误)

  • 比如:网络断开、服务器 500、JSON 解析失败、未捕获的运行时错误
  • 多半需要上报、告警,用户只看到通用错误提示

4.3 实战示例

async function placeOrder(orderData) {
  try {
    const res = await fetch('/api/order/create', {
      method: 'POST',
      body: JSON.stringify(orderData),
    });
    const text = await res.text();
    const data = safeParse(text, null);
    
    if (!res.ok) {
      // 业务异常:有明确的业务码和提示
      if (data?.code === 'BALANCE_INSUFFICIENT') {
        return { success: false, type: 'business', message: '余额不足,请先充值' };
      }
      if (data?.code === 'UNAUTHORIZED') {
        return { success: false, type: 'auth', message: '请先登录' };
      }
      // 其他 4xx/5xx
      return { success: false, type: 'system', message: data?.message || '服务器异常,请稍后重试' };
    }
    return { success: true, data };
  } catch (e) {
    // 系统异常:网络错误、JSON 解析异常等
    reportError(e);
    return { success: false, type: 'system', message: '网络异常,请检查网络后重试' };
  }
}

调用方可以这样区分:

const result = await placeOrder(formData);
if (result.success) {
  // 跳转支付/成功页
} else if (result.type === 'business' || result.type === 'auth') {
  message.warning(result.message); // 业务提示,用户可操作
} else {
  message.error(result.message); // 系统异常,建议稍后重试
}

五、实战中的几条规范

5.1 该用 try/catch 的地方

  1. JSON 解析:JSON.parse、res.json() 等容易抛错的地方
  2. 可能抛出异常的第三方库:如日期解析、复杂计算等
  3. 同步的、可能出错的业务逻辑:如参数校验、数据转换等

5.2 不要指望 try/catch 的地方

  1. 异步回调:用 Promise 的 .catch、async/await 的 try/catch 包住 await 那一行
  2. 事件监听:在回调里单独加 try/catch
  3. 全局错误:用 window.onerror 或 unhandledrejection 做兜底

5.3 一个完整的小案例

async function getProductDetail(id) {
  try {
    const res = await fetch(`/api/product/${id}`);
    const text = await res.text();
    const data = safeParse(text);
    
    if (!res.ok) {
      if (data?.code === 'NOT_FOUND') {
        return { ok: false, reason: 'product_not_found' };
      }
      throw new Error(data?.message || `请求失败:${res.status}`);
    }
    return { ok: true, data };
  } catch (e) {
    if (e.name === 'SyntaxError') {
      reportError(e, { context: 'JSON 解析', id });
      return { ok: false, reason: 'parse_error' };
    }
    if (e.message?.includes('fetch') || e.message?.includes('Network')) {
      return { ok: false, reason: 'network_error' };
    }
    throw e;
  }
}

六、总结

错误类型处理方式注意点
Ajax 网络错误try/catch + res.ok 判断4xx/5xx 不会自动抛异常
JSON 解析错误对 JSON.parse 包 try/catch建议封装 safeParse
业务异常根据 code 分支,返回固定结构给用户明确提示
系统异常catch 后上报 + 通用提示避免暴露内部错误细节
异步错误Promise .catch / async try不要指望外层同步 try 捕获

记住:不是所有错误都要用 try/catch,关键是区分'可预期业务失败'和'真正的异常',在合适的地方用合适的工具处理。

目录

  1. try/catch/Promise:前端错误处理实战
  2. 一、先搞清楚:try/catch 到底能抓到啥
  3. 1.1 能抓到的:同步代码里的异常
  4. 1.2 抓不到的:异步里的错误
  5. 二、fetch 错误:别只盯着 try/catch
  6. 2.1 fetch 是什么?
  7. 2.2 常见误解
  8. 2.3 正确做法
  9. 三、JSON 解析错误:最容易漏掉的一类
  10. 3.1 常见场景
  11. 3.2 推荐写法
  12. 四、业务异常 vs 系统异常:分类处理
  13. 4.1 业务异常(可预期的“业务失败”)
  14. 4.2 系统异常(程序/环境错误)
  15. 4.3 实战示例
  16. 五、实战中的几条规范
  17. 5.1 该用 try/catch 的地方
  18. 5.2 不要指望 try/catch 的地方
  19. 5.3 一个完整的小案例
  20. 六、总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Intel GPU 加速 llama.cpp:SYCL 后端完整配置与性能调优指南
  • YOLOv8/v11 与 LLM 联动的 Web 视觉检测系统:Django+Vue3 实战
  • AI 编程新范式:详解 Skills 概念及 Java 方法生成实战
  • 鸿蒙独立生态的三重挑战:兼容性、开发者意愿与全球市场突围
  • Vivado 许可证获取与配置实战指南
  • AI 模型底层逻辑:线性代数为何是核心语言
  • 宇树 G1 机器人二次开发:基于 FAST_LIO 的建图与配置实战
  • MySQL 分库分表实战:垂直分库与水平分表策略及分片键选择
  • EasyAI:Java 程序员的人工智能算法框架
  • GitHub 发布 MCP Server 项目最佳实践:架构、安全与自动化部署
  • Windows 11 本地部署 llama.cpp 运行 Qwen3.5 量化模型实测
  • Redis 数据结构 Set 实战:过滤用户注册重复提交信息
  • 基于 ModelScope 与 LLaMA-Factory 的大模型微调实战指南
  • Java 项目构建与管理:Maven 核心实战指南
  • AR 远程协作中的深度感知:基于 lingbot-depth-pretrain-vitl-14 的空间锚点实现
  • 入门安全:如何挖掘到第一个漏洞
  • Stable Diffusion 生成 AI 数字人视频教程
  • Vue Print Designer 前端可视化打印设计器详解
  • TRAE、Qoder、Cursor 与 Copilot:主流 AI 编程工具深度对比
  • LLM 大模型技术实战:入门大模型开发框架 LangChain

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online