渭南市网站建设_网站建设公司_React_seo优化
2026/1/13 19:11:28 网站建设 项目流程


Promise 吞错太坑?前端老鸟教你揪出那些藏起来的错误

  • Promise 吞错太坑?前端老鸟教你揪出那些藏起来的错误
    • 错误去哪了?—— 一场“无声”的坠机
    • Promise 为啥爱“吃白食”?
    • 现场还原:四个最容易踩的坑
      • 1. then 里 throw 完就跑
      • 2. async 函数里“裸奔”
      • 3. forEach + async 大杂烩——“并行”变“放飞”
      • 4. 只在最外层 catch——中间一层崩了依旧失联
    • 开发阶段:三招让错误“现行”
      • 1. 控制台开小灶
      • 2. 全局兜底——监听“漏网之鱼”
      • 3. ESLint 插件提前哔哔
    • 实战骚操作:让 catch 成为肌肉记忆
      • 1. async 函数“自动”try/catch 装饰器
      • 2. 请求库二次封装——统一吞错终结者
      • 3. Promise.allSettled —— “一个都不能少”
    • 测试/线上:错误真“蒸发”了怎么办?
    • 结尾掏心窝

Promise 吞错太坑?前端老鸟教你揪出那些藏起来的错误

“我代码明明跑通了,线上怎么还是白屏?”
“控制台干净得像刚洗的碗,结果用户截图里全是红的。”
别怀疑,90% 是 Promise 把错误吞了,还给你比了个耶。

今天不聊架构、不谈性能,就聊怎么把 Promise 偷偷咽下去的那些错误,像掏下水道一样,一根头发都别放过。坐稳,开掏。


错误去哪了?—— 一场“无声”的坠机

先整一个最简现场,三分钟复现:

// 假装这是个身家过亿的用户下单接口functionpay(money){returnfetch('/api/pay',{body:JSON.stringify({money})});}// 业务小哥潇洒调用pay(999).then(res=>res.json()).then(data=>console.log('支付成功',data));

看着没毛病?
实际上 fetch 只要状态码 ≥400 就走不到res.json(),而是抛错,可我们没 catch。
于是浏览器只在后台小声逼逼:“Uncaught (in promise)…”——用户看不到,监控收不到,你也浑然不觉
这就是“吞错”本吞:代码没崩,但业务崩了。


Promise 为啥爱“吃白食”?

Promise 的设计哲学一句话:“异步链式,自己管自己”
它相信“后面一定会有人 catch 我”,结果很多人就是忘了那个“人”。

  1. 链式里任意一步抛错,只要没 catch,错误就顺着链一路飘到太空。
  2. async/await 只是 Promise 的语法糖,本质还是 Promise,不写 try/catch 一样白给。
  3. 微任务队列把异常推迟到“当前调用栈清空”之后才抛,导致断点打不到、日志看不清

现场还原:四个最容易踩的坑

1. then 里 throw 完就跑

Promise.resolve().then(()=>{thrownewError('我裂开了');// 抛了,但没人接}).then(data=>console.log('永远到不了这'));// 控制台:Uncaught (in promise) Error: 我裂开了

解决:给链尾加个“垃圾桶”——catch。

Promise.resolve().then(()=>{thrownewError('我裂开了');}).catch(err=>console.error('逮住',err));

2. async 函数里“裸奔”

asyncfunctionload(){constres=awaitfetch('/api/xxx');// 这里 404 了constdata=awaitres.json();// 实际上走到这行才炸returndata;}load();// 没有 await,没有 try/catch,错误秒变“幽灵”

解决:要么调用方 try/catch,要么内部兜底:

asyncfunctionload(){try{constres=awaitfetch('/api/xxx');if(!res.ok)thrownewError(res.status);returnawaitres.json();}catch(e){console.error('load 炸了',e);throwe;// 继续往外抛,让调用方决定}}

3. forEach + async 大杂烩——“并行”变“放飞”

[1,2,3].forEach(asyncn=>{awaitdelay(100);thrownewError(`${n}个雷`);});// 控制台干净得能照镜子

forEach 的回调里 async 语法完全合法,但 forEach 不会等你,回调里抛错也没人帮你接
解决:老老实实 for…of,或者 Promise.all 包一层。

asyncfunctionboom(){awaitPromise.all([1,2,3].map(asyncn=>{awaitdelay(100);thrownewError(`${n}个雷`);}));}boom().catch(e=>console.error('被抓住',e));

4. 只在最外层 catch——中间一层崩了依旧失联

fetchData().then(()=>{returnprocess();// 这里抛错}).then(()=>{returnsave();// 这里也抛错}).catch(e=>console.error('save 异常',e));

如果process()抛错,能 catch 住;
但如果save()抛错,前面 then 里 return 的 Promise 没链式返回,一样失联。
解决:链式返回 + 每层可选 catch,或者 async/await 一把梭。


开发阶段:三招让错误“现行”

1. 控制台开小灶

Chrome → 控制台齿轮 → 勾上“Pause on caught exceptions”
只要有 Promise 抛错,直接断点,调用栈一目了然。

2. 全局兜底——监听“漏网之鱼”

浏览器:

window.addEventListener('unhandledrejection',e=>{console.error('捕获未处理的 Promise 拒绝:',e.reason);// 上报监控report('/monitor/lp',{msg:e.reason.stack||e.reason});});

Node:

process.on('unhandledRejection',(reason,promise)=>{console.error('未处理拒绝',promise,reason);// 别让进程挂得不明不白});

3. ESLint 插件提前哔哔

eslint-plugin-promise+@typescript-eslint/no-floating-promises
一保存就把“裸 Promise”标红,比你领导还严格


实战骚操作:让 catch 成为肌肉记忆

1. async 函数“自动”try/catch 装饰器

functionsafe(target,key,descriptor){constfn=descriptor.value;descriptor.value=asyncfunction(...args){try{returnawaitfn.apply(this,args);}catch(e){console.error(`[${key}] 异常`,e);throwe;// 继续外抛,防止静默}};}classService{@safeasyncloadConfig(){constres=awaitfetch('/api/config');returnawaitres.json();}}

一个装饰器,全员保险,队友再也写不出“裸 async”。

2. 请求库二次封装——统一吞错终结者

functionrequest(url,options={}){returnfetch(url,{...options,credentials:'include'}).then(asyncres=>{consttext=awaitres.text();letdata;try{data=JSON.parse(text);}catch{data=text;}if(!res.ok){consterr=newError(res.statusText);err.status=res.status;err.data=data;returnPromise.reject(err);}returndata;}).catch(err=>{console.error('request 错误',err);report('/monitor/request',{url,msg:err.message});throwerr;// 继续外抛,业务层还能 catch});}

以后全团队都用request网络错误再也不是黑盒

3. Promise.allSettled —— “一个都不能少”

老伙计Promise.all只要有一个 reject,全员翻车
allSettled让每个人无论生死都回传成绩单

consttasks=[fetch('/api/a'),fetch('/api/b'),fetch('/api/c')];constres=awaitPromise.allSettled(tasks);res.forEach((r,i)=>{if(r.status==='rejected'){console.error(`任务${i}挂了`,r.reason);}else{console.log(`任务${i}成功`,r.value);}});

测试/线上:错误真“蒸发”了怎么办?

  1. 先排除测试环境把console.error重写为空函数 ——有些 CI 默认静音
  2. 检查是否用了“友好错误页”组件,把异常吃干抹净又不打印
  3. 确认监控脚本是不是只收window.onerror,没收unhandledrejection——漏掉一半场景
  4. 本地复现不开缓存,把 Network 面板 “Disable cache” 勾上,防止 304 干扰。
  5. 如果错误“延迟”出现,在本地开 Performance 面板录一段,看是不是微任务队列“晚点”抛错。

结尾掏心窝

Promise 这哥们儿并不坏,它只是“信任你太满”。
你忘了 catch,它就真敢把错误带跑路;
你多问一句“要是崩了呢?”,它就老老实实把错误递到你手里。

写异步代码前,给自己加个弹幕:“待会儿要是这里炸了,我能收到微信吗?”
收不到?那就补 catch、加监听、上监控,千万别等用户截图甩群里才后知后觉

愿你今后每个 reject 都被温柔以待,
愿线上永远不再出现“神秘白屏”——
catch 到位,头发不掉,回见!

欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!


专栏系列(点击解锁)学习路线(点击解锁)知识定位
《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等
《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结
《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识
《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心
《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页
《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化
《Vue实战相关博客》持续更新中~详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅
《python相关博客》持续更新中~Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具
《sql数据库相关博客》持续更新中~SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能
《算法系列相关博客》持续更新中~算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维
《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识
《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方
《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面
《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等
《photoshop相关博客》持续更新中~基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结
日常开发&办公&生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询