优雅降级关键在于分层处理错误:网络层异常(如fetch失败)由try-catch捕获,业务层异常(如status≠200、code≠0)需手动throw;统一校验逻辑封装在高阶函数中,逐层检查并明确抛错;按业务重要性分级降级,核心链路透出错误,非核心模块可返回默认值;并行请求优先用promise.allsettled配合独立降级策略。

直接在 async 函数里写 try-catch 并不能自动覆盖所有错误场景,尤其当错误来自 HTTP 状态码、业务返回码或异步回调内部时。真正实现优雅降级,关键在于明确错误分层、主动校验、统一收口,而不是依赖 try-catch 被动兜底。
区分网络层与业务层错误
两类错误必须分开处理,混为一谈会导致“请求成功却逻辑失败”:
- 网络层异常:fetch 失败、超时、DNS 解析失败、TypeError: Failed to fetch —— 这类会被 await 捕获,属于真正的 JS 异常
- 业务层异常:response.status !== 200(如 401/500)、响应体中 data.code !== 0、data.message 提示失败 —— 这不是 JS 异常,await 不会触发 catch,必须手动 throw
用高阶函数封装统一校验逻辑
把 fetch、解析、业务码判断全收进一个函数,在 try 块内逐层检查,确保任一环节出问题都进入统一错误处理流:
- 传入的是函数 promiseFn,而非已执行的 Promise,避免副作用和无法拦截
- 先校验 res.ok,再 await res.json(),最后检查 data.code
- 每一步失败都 throw 明确错误(保留原始类型),不静默吞掉
- catch 中做日志、上报、UI 提示,但通常仍 re-throw,让调用方决定是否继续捕获或降级
按需降级,不强求全局静默
不是所有错误都要“吃掉”,要结合业务重要性分级处理:
- 核心链路(如登录、下单):错误应透出,用户需感知并重试,不建议在底层 catch 后返回默认值
- 非核心模块(如推荐位、统计埋点、头像加载):可在调用层单独 try-catch,捕获后返回空数组、占位图或缓存数据,保障主流程不中断
- 避免在公共请求函数里对所有错误统一返回 {} 或 [],这会让上层失去判断依据
配合 Promise.allSettled 处理并行请求
当多个请求互不影响(如首页同时拉用户、订单、通知),用 allSettled 更自然:
- 每个请求可独立封装成带降级逻辑的函数(例如 fetchWithFallback)
- allSettled 返回每个结果的状态(fulfilled/rejected),按 status 分支处理,失败时走各自降级策略
- 比层层 try-catch 嵌套更清晰,也避免了某个请求失败导致整组请求被 cancel











