Promise
定义
Promise是JavaScript中的一种对象,代表一次异步操作在将来产生的结果或失败原因。按Promises/A+规范的定义,与Promise交互的主要入口是它的then方法,调用方通过该方法登记回调,以便在操作成功时取回值、在失败时取回失败原因。这种对象把「结果还没到」这件事本身变成可以传递、可以等待的普通值,因此异步任务的调度逻辑不必写在回调内部。
状态是Promise定义中的核心。一个Promise只能处于pending(进行中)、fulfilled(已成功)与rejected(已失败)三种状态之一;处于pending时可以转向另外两种之一,一旦进入fulfilled或rejected,就不能再转向任何其他状态,并分别固定持有一个值或一个失败原因。状态确定且值固定的Promise在社区文档中常被合称为settled,中文常译作已定型[3]。
原理
Promise通过构造函数创建,构造时传入一个执行器函数,执行器同步获得resolve与reject两个函数作为参数,自行在异步操作结束时调用其中之一[4]。执行器返回的值会被忽略;如果在执行器中抛出错误,且尚未调用resolve或reject,该Promise转为已失败状态[4]。若执行器既不调用这两个函数、又不安排任何异步任务,Promise就会永久停留在进行中状态[4]。
then方法接受onFulfilled与onRejected两个可选参数,两者都必须等到当前执行栈只含平台代码之后才可被调用,且成功或失败回调各自最多执行一次。同一个Promise上多次调用then时,回调按登记顺序依次执行;then本身返回一个新的Promise,若回调返回了值x,则按解析过程处理,若x本身是一个thenable或Promise,新Promise会跟随x的最终状态。这一「返回新Promise」的规则是链式写法成立的前提。
回调进入微任务队列而非立即执行,是Promise时序的关键。即使Promise已经确定,then登记的函数也不会同步运行,而是排入微任务,在当前任务结束、执行栈清空后运行。因此同步代码先输出、then回调后输出的顺序可以稳定复现。错误在链中具有传递性质:某一环被拒绝且没有处理函数时,拒绝原因会继续向后传给下一个处理函数。
除实例方法外,Promise构造函数还提供组合多个任务的静态方法。Promise.all在所有输入的Promise都成功时以结果数组兑现,任一失败即立刻以该原因拒绝;Promise.allSettled则等待全部操作结束再汇总为数组。Promise.race以最先确定的那一个Promise的状态为准,Promise.any则以最先成功的一个为准。
发展历程
Promise并非JavaScript独创的机制。按社区梳理,这一概念可追溯到1976年的相关研究,其思想与future、延迟计算等构造同源,此后在多种语言的并发库中以std::promise、Future等形式出现[3]。在JavaScript生态中,较早被广泛使用的类似实现是jQuery的Deferred对象,但它与后来的规范并不完全一致[3]。
为了在不同实现之间达成互操作,2012年形成了Promises/A+这一开放规范,它只规定then方法的行为,并附带测试用例,从而使各家Promise库可以互相替换使用。在该标准进入语言规范之前,社区已出现Q、bluebird、when等遵循该规范的库[5]。
ECMAScript 2015(即ES6)把Promise纳入语言标准,浏览器与Node.js随后原生提供该对象,Mozilla基金会的开发者文档将浏览器全面支持的时间点记为2015年7月[4][2]。在此基础上,ES2017引入的async函数与await运算符以Promise为底层机制,异步代码可以写成接近同步的分支与循环结构[3]。
应用
最常见的用途是发起网络请求并处理其响应。现代浏览器提供的Fetch API返回Promise,网络成功与否用状态表示,响应内容再通过then或await取出[3]。在没有原生Promise接口的旧式回调API上,通常用构造函数把回调包装成Promise,从而统一调用方式;例如把setTimeout包装为返回Promise的等待函数。
串行流程可以用then链表达:前一环返回新的Promise,后一环即在其完成后执行,从而避免层层缩进的回调嵌套,并在链尾用catch集中处理前面各环节的错误。并行且互不依赖的任务则交给Promise.all,待全部结果就绪后一并处理,常见的做法是同时请求多份数据再统一渲染[3]。
Promise也作为基础设施支撑了多项平台能力与框架设计。JavaScript指南列举的组合工具都已建立在Promise之上,服务端的数据库驱动与Web框架同样以Promise作为异步接口的默认形态[3]。在资源预加载、超时控制等场景中,Promise.race可以把请求与计时器放在一起竞速,由先结束的一方决定后续流程[6]。
局限
Promise本身没有取消协议。规范与标准文档都没有提供取消已建立Promise的接口,一旦创建即开始执行,无法从外部中途终止,只能通过resolve或reject改变状态[1]。实践中通常借助AbortController去取消底层的异步操作,而非取消Promise对象本身。
在进行中状态下,外部无法得知任务进展到哪一步,只能等待最终结果,因此不适合用来表达持续产生多个值的流式场景[1]。此外,若某个Promise被拒绝而始终没有附加处理函数,该失败不会自动向调用方传播,需要运行环境额外上报:浏览器会在全局作用域派发unhandledrejection事件,Node.js则触发同名的进程事件[7][8]。
组合方法也有边界。Promise.all在遇到第一个失败时即整体拒绝,其余操作虽仍在执行,但其结果不会再通过该Promise返回,这可能造成不易察觉的状态残留;需要全部结束的场合应改用Promise.allSettled。另外,把互不依赖的任务用then串行排布会让它们相互阻塞,在不需要顺序的地方应保持并行。
参见
参考资料
- Promise 对象 [引用日期2026-10-29]
- educative.io 上的网页 [引用日期2026-10-29]
- Promise的前世今生 [引用日期2026-10-29]
- Promise() 构造函数 [引用日期2026-10-29]
- 请选择投诉理由 [引用日期2026-10-29]
- Javascript 中的神器——Promise [引用日期2026-10-29]
- Window: unhandledrejection 事件 [引用日期2026-10-29]
- 事件:'unhandledRejection'#>>>>>>>>>>> [引用日期2026-10-29]