async/await 实战规范:错误处理、避免嵌套、防重复请求,异步最佳实践|编码语法规范篇
【async/await】【中后台前端业务】从规范写法到实战落地彻底搞懂异步代码最佳实践避开错误丢失、嵌套混乱、重复请求高频坑 文章目录一、写在前面为什么要认真学 async/await二、基础扫盲async/await 到底是什么2.1 一句话理解2.2 一个最简单的例子2.3 易混点async 函数一定返回 Promise三、错误处理必须掌握 try/catch3.1 不用 try/catch 会怎样3.2 正确姿势try/catch 包裹 await3.3 多个 await 只写一个 try/catch3.4 分别处理不同错误多段 try/catch四、避免嵌套能平铺就平铺4.1 反面教材回调式嵌套4.2 推荐提前 return减少嵌套4.3 无依赖的请求用 Promise.all 并行4.4 部分并行、部分串行五、防重复请求节流 / 防抖 请求标识5.1 典型场景连续点击“提交”按钮5.2 方案一loading 锁简单实用5.3 方案二AbortController 取消上一次请求5.4 方案三请求去重相同请求只发一次六、综合示例一个相对规范的异步函数七、常见坑与注意点八、小结 系列模块导航同学们好我是 Eugene尤金一名多年中后台前端开发工程师。Eugene 发音 /juːˈdʒiːn/大家怎么顺口怎么叫就好很多前端开发者都会遇到一个瓶颈代码能跑但不够规范功能能实现但维护起来特别痛苦一个人写没问题一到团队协作就各种混乱、踩坑、返工。想写出干净、优雅、可维护的专业代码靠的不是天赋而是体系化的规范 真实实战经验。这一系列《前端规范实战》我会用大白话 真实业务场景不讲玄学、不堆理论只分享能直接落地的规范、标准与避坑指南。帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。一、写在前面为什么要认真学 async/await不管你是刚入门的前端还是已经写了几年 JS 的熟手都容易在异步代码上踩坑回调地狱、错误难定位、重复请求、逻辑嵌套过深……async/await 是 ES2017 引入的语法糖核心作用就两条让异步代码看起来像同步代码同时让异步逻辑更容易理解和维护。本文不讲晦涩的底层实现而是围绕日常怎么写、为什么这么写、容易踩什么坑。看完后你会对错误处理避免嵌套防重复请求有清晰的实践规范。⬆ 返回目录二、基础扫盲async/await 到底是什么2.1 一句话理解async把一个函数标成“异步函数”函数内可以用 await。await只能在 async 函数里用用来“等待”一个 Promise等完再往下执行。⬆ 返回目录2.2 一个最简单的例子// 假设 fetchUser 是一个返回 Promise 的接口请求asyncfunctiongetUserInfo(){constuserawaitfetchUser(123);console.log(user.name);returnuser;}等价于functiongetUserInfo(){returnfetchUser(123).then(user{console.log(user.name);returnuser;});}区别在于await 写法是自上而下的顺序更接近同步思维阅读和调试都更直观。⬆ 返回目录2.3 易混点async 函数一定返回 PromiseasyncfunctionsayHi(){return你好;}// 等价于functionsayHi(){returnPromise.resolve(你好);}所以constresultawaitsayHi();// result 是 你好sayHi().then(resconsole.log(res));// 也可以因为返回的是 Promise⬆ 返回目录三、错误处理必须掌握 try/catch3.1 不用 try/catch 会怎样asyncfunctiongetData(){constdataawaitfetchApi(/api/list);// 如果接口报错 500console.log(data);// 不会执行returndata;}getData();// Unhandled promise rejection! 控制台一片红未捕获的 Promise 拒绝会导致Unhandled promise rejection错误容易“消失”在调用链里难以排查。⬆ 返回目录3.2 正确姿势try/catch 包裹 awaitasyncfunctiongetData(){try{constdataawaitfetchApi(/api/list);console.log(data);returndata;}catch(error){console.error(请求失败:,error);// 这里可以做弹提示、上报日志、返回兜底数据等throwerror;// 或者继续往上抛}}⬆ 返回目录3.3 多个 await 只写一个 try/catch可以。一次 try/catch 会捕获这段代码块内任意一个await 抛出的错误asyncfunctioninitPage(){try{constuserawaitfetchUser();constlistawaitfetchList();constconfigawaitfetchConfig();// 任意一步报错都会跳到 catchreturn{user,list,config};}catch(error){console.error(初始化失败:,error);throwerror;}}⬆ 返回目录3.4 分别处理不同错误多段 try/catchasyncfunctioninitPage(){letusernull;letlist[];try{userawaitfetchUser();}catch(error){console.error(用户信息获取失败,error);user{name:游客};// 兜底}try{listawaitfetchList();}catch(error){console.error(列表获取失败,error);// 列表失败可以保持空数组}return{user,list};}按需选择统一处理用一段 try/catch差异化处理用多段。⬆ 返回目录四、避免嵌套能平铺就平铺4.1 反面教材回调式嵌套asyncfunctionbadExample(){constuserawaitfetchUser();if(user){constordersawaitfetchOrders(user.id);if(orders.length0){constdetailawaitfetchOrderDetail(orders[0].id);// 继续嵌套...}}}虽然比回调地狱好但层级一多可读性还是会变差。⬆ 返回目录4.2 推荐提前 return减少嵌套asyncfunctiongoodExample(){constuserawaitfetchUser();if(!user)returnnull;constordersawaitfetchOrders(user.id);if(orders.length0)return[];constdetailawaitfetchOrderDetail(orders[0].id);returndetail;}逻辑是一条直线心智负担更小。⬆ 返回目录4.3 无依赖的请求用 Promise.all 并行// 串行慢asyncfunctionslowWay(){constuserawaitfetchUser();constlistawaitfetchList();constconfigawaitfetchConfig();return{user,list,config};}// 并行快asyncfunctionfastWay(){const[user,list,config]awaitPromise.all([fetchUser(),fetchList(),fetchConfig()]);return{user,list,config};}只要这几个请求互不依赖就可以并行整体耗时 ≈ 最慢的那个请求。⬆ 返回目录4.4 部分并行、部分串行asyncfunctionmixedWay(){// 先并行拿 user 和 configconst[user,config]awaitPromise.all([fetchUser(),fetchConfig()]);// 再用 user.id 拿列表依赖 userconstlistawaitfetchList(user.id);return{user,list,config};}⬆ 返回目录五、防重复请求节流 / 防抖 请求标识5.1 典型场景连续点击“提交”按钮// 不处理点几次发几次asyncfunctionhandleSubmit(){constdataawaitsubmitForm(formData);message.success(提交成功);}⬆ 返回目录5.2 方案一loading 锁简单实用letisSubmittingfalse;asyncfunctionhandleSubmit(){if(isSubmitting)return;isSubmittingtrue;try{constdataawaitsubmitForm(formData);message.success(提交成功);}catch(error){message.error(提交失败);}finally{isSubmittingfalse;// 无论成功失败都要解锁}}在 Vue 里通常用loading状态constloadingref(false);asyncfunctionhandleSubmit(){if(loading.value)return;loading.valuetrue;try{awaitsubmitForm(formData);message.success(提交成功);}catch(error){message.error(提交失败);}finally{loading.valuefalse;}}⬆ 返回目录5.3 方案二AbortController 取消上一次请求适用场景搜索联想、下拉加载等只关心最后一次请求的结果letabortControllernull;asyncfunctionsearch(keyword){// 取消上一次未完成的请求if(abortController){abortController.abort();}abortControllernewAbortController();try{constresawaitfetch(/api/search?q${keyword},{signal:abortController.signal});constdataawaitres.json();returndata;}catch(error){if(error.nameAbortError){return;// 被取消不处理}throwerror;}}⬆ 返回目录5.4 方案三请求去重相同请求只发一次多个组件同时请求同一数据时可做“请求合并”或“共享 Promise”constrequestCachenewMap();asyncfunctionfetchWithDedup(url){if(requestCache.has(url)){returnrequestCache.get(url);}constpromisefetch(url).then(resres.json()).finally((){requestCache.delete(url);});requestCache.set(url,promise);returnpromise;}这样同一时刻对同一 url 的多次调用只会发一次请求。⬆ 返回目录六、综合示例一个相对规范的异步函数asyncfunctionloadPageData(pageId){// 1. 防重复if(loading.value)return;loading.valuetrue;try{// 2. 并行无依赖请求const[pageInfo,userInfo]awaitPromise.all([fetchPageInfo(pageId),fetchUserInfo()]);// 3. 提前 return减少嵌套if(!pageInfo){message.error(页面不存在);return;}// 4. 有依赖的请求串行constlistawaitfetchList(pageInfo.listId);return{pageInfo,userInfo,list};}catch(error){console.error(页面加载失败:,error);message.error(加载失败请重试);throwerror;}finally{loading.valuefalse;}}要点回顾使用 loading 防止重复提交无依赖请求用Promise.all并行用提前 return 减少嵌套统一 try/catch 处理错误用finally保证 loading 一定会被还原⬆ 返回目录七、常见坑与注意点7.1 在循环里误用 await// 串行执行可能不是预期for(constidofids){constitemawaitfetchItem(id);result.push(item);}// 需要并行时constresultawaitPromise.all(ids.map(idfetchItem(id)));7.2 忘记 awaitasyncfunctionbug(){constdatafetchData();// 没有 awaitconsole.log(data);// 输出的是 Promise不是数据}7.3 在非 async 函数里用 awaitfunctionwrong(){constdataawaitfetchData();// SyntaxError}await 只能在 async 函数或 top-level await 环境里使用。⬆ 返回目录八、小结错误处理用 try/catch 包裹 await必要处用finally做收尾。结构能平铺就平铺少嵌套无依赖请求用Promise.all并行。防重复提交类用 loading 锁搜索类用 AbortController可再考虑请求去重。细节循环里按需选择串行/并行别忘记 awaitawait 只能在 async 里用。先把这些习惯养成再结合项目逐步实践你的异步代码会清晰、稳健很多。⬆ 返回目录 系列模块导航 编码语法规范这是前端规范实战系列中第二个模块当编码语法规范模块更新完成之后会附上此模块的跳转链接方便同学们阅读学习。更新中敬请期待~ 跟着系列慢慢学把技术功底扎扎实实地打牢 系列总览前端规范实战系列目前正在持续更新中当该系列完结之后我会整理出一篇《前端规范实战系列全系列目录导航》,届时会附上文章简介以及跳转链接方便同学们按顺序体系化的学习~更新中敬请期待~⬆ 返回目录同学们好我是 Eugene尤金一名多年中后台前端开发工程师。Eugene 发音 /juːˈdʒiːn/大家怎么顺口怎么叫就好很多前端开发者都会遇到一个瓶颈代码能跑但不够规范功能能实现但维护起来特别痛苦一个人写没问题一到团队协作就各种混乱、踩坑、返工。想写出干净、优雅、可维护的专业代码靠的不是天赋而是体系化的规范 真实实战经验。这一系列《前端规范实战》我会用大白话 真实业务场景不讲玄学、不堆理论只分享能直接落地的规范、标准与避坑指南。帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2430820.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!