JavaScript 的异步管家:彻底搞懂 Promise 原型方法
为什么需要 Promise在 ES6 之前处理异步操作如网络请求、定时器主要靠回调函数Callback。当逻辑复杂时容易陷入“回调地狱”Callback Hell代码嵌套层级深难以维护。通俗比喻想象你去餐厅点餐发起异步请求。回调地狱模式你站在柜台前服务员说“等菜好了叫你”你不敢走菜好了服务员说“等汤好了叫你”你还得站着……直到所有流程结束。Promise 模式服务员给你一张取餐号小票Promise 对象。你可以去旁边坐着玩手机执行其他代码。如果菜做好了成功服务员叫号你去取餐.then。如果菜卖完了失败服务员道歉你决定换一家或吃泡面.catch。无论成功还是失败最后都要把桌子收拾干净.finally。这张“小票”及其附带的服务规则就是Promise 原型上的方法。 目录️ 核心概念Promise 的状态机 实例方法处理结果与异常 静态方法并发控制与工具函数 代码实战常见场景演练⚠️ 常见误区与最佳实践 总结1. ️ 核心概念Promise 的状态机Promise 对象代表一个异步操作的最终完成或失败及其结果值。它有三种状态且状态一旦改变不可逆状态英文说明Pending进行中初始状态既不是成功也不是失败。Fulfilled已成功操作成功完成有一个值。Rejected已失败操作失败有一个原因错误信息。注意我们通常调用的.then(),.catch()等方法都是挂载在Promise.prototype上的实例方法。而Promise.all(),Promise.race()等是挂载在Promise构造函数上的静态方法。2. 实例方法处理结果与异常这些方法用于注册回调当 Promise 状态改变时被调用。✅ 1..then(onFulfilled, onRejected)作用指定Resolved和Rejected状态的回调函数。返回值返回一个新的 Promise 对象。这使得我们可以进行链式调用。参数onFulfilled: 可选成功时的回调。onRejected: 可选失败时的回调通常建议用.catch代替。constpromisenewPromise((resolve,reject){setTimeout(()resolve(数据加载成功),1000);});promise.then((value){console.log(value);// 数据加载成功returnvalue - 处理完毕;// 返回值会传递给下一个 then}).then((newValue){console.log(newValue);// 数据加载成功 - 处理完毕});✅ 2..catch(onRejected)作用专门处理 Rejected 状态或链式中抛出的错误。本质它是.then(null, onRejected)的语法糖。优势可以捕获前面所有.then中发生的同步错误。promise.then((value){thrownewError(处理过程中出错了);}).catch((error){console.error(error.message);// 处理过程中出错了});✅ 3..finally(onFinally)作用无论 Promise 最终是 Fulfilled 还是 Rejected都会执行的回调。场景关闭 Loading 动画、隐藏弹窗、清理资源等。注意onFinally不接受参数也不影响最终的返回值除非抛出错误。letisLoadingtrue;fetch(/api/data).then((res)res.json()).catch((err)console.error(err)).finally((){isLoadingfalse;// 无论成功失败都停止加载状态console.log(请求结束);});3. 静态方法并发控制与工具函数这些方法直接挂在Promise构造函数上用于创建或组合多个 Promise。✅ 1.Promise.resolve(value)作用快速创建一个状态为 Fulfilled 的 Promise。场景将普通值或非 Promise 对象包装成 Promise以便统一使用.then处理。Promise.resolve(Hello).then((val)console.log(val));// Hello✅ 2.Promise.reject(reason)作用快速创建一个状态为 Rejected 的 Promise。场景在函数开头进行参数校验失败时直接返回拒绝态。functioncheckAge(age){if(age18){returnPromise.reject(未成年人禁止访问);}returnPromise.resolve(访问允许);}✅ 3.Promise.all(iterable)【高频面试点】作用并行执行多个 Promise所有都成功才成功任何一个失败则立即失败。返回值一个包含所有结果的数组顺序与输入一致。场景同时请求用户信息和订单列表两者都拿到后才渲染页面。constp1Promise.resolve(1);constp2Promise.resolve(2);constp3Promise.reject(Error);// 全部成功Promise.all([p1,p2]).then((values)console.log(values));// [1, 2]// 有一个失败Promise.all([p1,p3]).catch((err)console.error(err));// Error✅ 4.Promise.race(iterable)作用并行执行多个 Promise谁先改变状态无论成功还是失败就采用谁的结果。场景超时控制。比如请求接口如果 5秒 没返回就判定超时。constrequestfetch(/api/slow-data);consttimeoutnewPromise((_,reject)setTimeout(()reject(请求超时),5000),);Promise.race([request,timeout]).then((res)console.log(成功,res)).catch((err)console.error(失败,err));✅ 5.Promise.allSettled(iterable)【ES2020】作用并行执行多个 Promise等待所有任务结束不管成功还是失败。返回值一个对象数组每个对象包含status(‘fulfilled’ 或 ‘rejected’) 和value/reason。场景批量上传文件想知道哪些成功了哪些失败了而不是因为一个失败就全盘否定。constp1Promise.resolve(1);constp2Promise.reject(Fail);Promise.allSettled([p1,p2]).then((results){results.forEach((result){if(result.statusfulfilled){console.log(成功:,result.value);}else{console.log(失败:,result.reason);}});});// 输出:// 成功: 1// 失败: Fail✅ 6.Promise.any(iterable)【ES2021】作用并行执行多个 Promise只要有一个成功就返回那个成功的结果。只有全部失败才返回失败聚合错误。场景从多个镜像源下载资源哪个快用哪个。4. 代码实战常见场景演练场景 1串行依赖请求Chain第二个请求依赖第一个请求的结果。getUserInfo(userId).then((user){returngetOrderList(user.id);// 返回新的 Promise}).then((orders){console.log(用户订单:,orders);}).catch((err){console.error(流程出错:,err);});场景 2并行独立请求All两个请求互不依赖同时发起以节省时间。Promise.all([getBannerData(),getRecommendList()]).then(([banners,recommends]){renderPage(banners,recommends);}).catch((err){showToast(页面加载失败);});场景 3带超时的请求封装functionfetchWithTimeout(url,timeout5000){constcontrollernewAbortController();constidsetTimeout(()controller.abort(),timeout);returnfetch(url,{signal:controller.signal}).then((res){clearTimeout(id);returnres.json();}).catch((err){if(err.nameAbortError){thrownewError(请求超时);}throwerr;});}5. ⚠️ 常见误区与最佳实践❌ 误区 1在.then中忘记return如果在.then中返回了一个普通的值下一个.then能收到但如果返回了一个 Promise下一个.then会等待这个 Promise 结算。如果不 return后续链条可能拿到undefined。❌ 误区 2混淆Promise.all和Promise.allSettled如果你希望“要么全成要么全败”用all。如果你希望“不管成败我都要知道每个任务的结果”用allSettled。✅ 最佳实践始终使用.catch或try...catch未处理的 Promise rejection 会导致控制台警告甚至在 Node.js 进程中导致退出。// Async/Await 风格下的错误处理asyncfunctionloadData(){try{constdataawaitfetch(/api/data);// ...}catch(error){console.error(捕获异常:,error);}}✅ 最佳实践避免嵌套.then尽量保持扁平化的链式调用或者直接使用async/await后者可读性更好。6. 总结方法类型方法名核心作用关键特点实例方法.then()处理成功/失败链式调用返回新 Promise.catch()处理异常捕获前面所有的错误.finally()最终清理必执行无参数静态方法Promise.resolve()创建成功态包装值Promise.reject()创建失败态包装错误Promise.all()并行全成功短路与一错即错Promise.race()竞速谁快听谁的Promise.allSettled()并行全结算记录每个任务状态Promise.any()竞速成功只要一个成功即可 博主寄语Promise 是现代 JavaScript 异步编程的基石。虽然async/await让代码看起来像同步的但理解底层的 Promise 原型方法特别是all和race的区别对于处理复杂并发场景至关重要。记住口诀Then 链式传值忙Catch 兜底防异常。All 要全都成功样Race 抢跑第一强。Settled 不管成与败Any 只要一个亮。Finally 最后收个场异步编程心不慌。希望这篇文档能帮你彻底掌握 Promise 的原型方法如果有疑问欢迎在评论区留言。喜欢这篇文章吗记得点赞、收藏、转发哦❤️