Promise
promise
表示一个异步操作的最终结果。和一个 promise
进行交互的主要方式是通过它的 then
方法,该方法注册回调要么接收一个 promise
的最终值,要么接收 promise
为什么不能被满足的原因。
规范
-
术语
promise
是一个带有then
方法的对象或函数,其行为符合此规范。thenable
是一个定义了then
方法的对象或函数。value
是任何合法的JavaScript
值(包括undefined
、thenable
或promise
)。exception
是使用throw
语句抛出的值。reason
是一个值,它指示为什么一个承诺被拒绝。
-
要求
-
promise
状态-
pending
:等待状态- 当处于等待状态时可以转化成
fulfilled
/rejected
- 当处于等待状态时可以转化成
-
fulfilled
:完成状态- 一定不能转换成其他状态
- 必须有一个不能转换的值(
value
)
-
rejected
:拒绝状态- 一定不能转换成其他状态
- 必须又一个不能转换的原因(
reason
)
-
-
then
方法:一个promise
必须提供一个then
方法来访问它的当前或最终值(value
)或原因(reason
),then
方法接收两个参数promise.then(onFulfilled, onRejected)
-
onFulfilled
和onRejected
都是可选的参数- 如果
onFulfilled
不是个函数,必须被忽略 - 如果
onRejected
不是个函数,必须被忽略
- 如果
-
如果
onFulfilled
是一个函数- 必须在
promise
完成(resolve
)后被调用,promise
的值(value)作为它第一个参数 - 一定不能在
promise
完成(resolve
)前被调用 - 一定不能被调用多次
- 必须在
-
如果
onRejected
是一个函数- 必须在
promise
拒绝(reject
)后被调用,promise
的值(reason)作为它第一个参数 - 一定不能在
promise
拒绝(reject
)前被调用 - 一定不能被调用多次
- 必须在
-
在执行上下文堆栈只包含平台代码
[3.1]
之前,不能调用onfulfilled
或onRejected
-
onFulfilled
和onRejected
必须作为函数调用(没有this
值)[3.2]
-
同一个
promise
上的then
可能被多次调用- 如果
promise
被完成(resolve
),所有相应的onFulfilled
需要按照then
的顺序被顺序执行 - 如果
promise
被拒绝(reject
),所有相应的onRejected
需要按照then
的顺序被顺序执行
- 如果
-
then
必须返回一个promise
实例[3.3]
promise2 = promise1.then(onFulfilled, onRejected)
- 如果
onFulfilled
和onRejected
返回一个值x
,运行[[Resolve]](promise2, x)
- 如果
onFulfilled
和onRejected
抛出一个异常e
,promise2
必须要用e
作为理由拒绝 - 如果
onFulfilled
不是一个函数并且promise1
被完成(resolve
),promise2
需要返回跟promise1
同样的值 (value
) - 如果
onRejected
不是一个函数并且promise1
被拒绝(reject
),promise2
需要返回跟promise1
同样的值 (reason
)
- 如果
-
-
promise
解决程序([[Resolve]]
)[[Resolve]]
是一个抽象的概念,它一个promise
和x
作为输入[[Resolve]](promise, x)
,如果x
是一个thenable
,它试图让承诺采用x
的状态,假设x
至少表现得有点像一个promise
。否则,它将使用值x来实现promise
,这种thenable
的处理允许promise
的实现更具有通用型,只要它们暴露一个遵守Promise/A+
的then
方法即可。它还允许遵守Promise/A+
规范的实现可以与那些不太规范但是可用的实现进行共存,运行[[Resolve]](promise, x)
,执行以下步骤-
如果
promise
和x
指向同一个对象,则以TypeError
作为原因拒绝promise
-
如果
x
是一个promise
则采取它的状态[3.4]
- 如果
x
状态是pending
,则promise
必须持续pending
,直到x
被完成或拒绝。 - 如果
x
状态是resolve
,则用相同的值(value)解决promise
- 如果
x
状态是reject
,则用相同的原因(reason)拒绝promise
- 如果
-
如果
x
是一个函数或者对象- 使
then
的值为x.then
[3.5]
- 如果获取
x.then
的值抛出异常e
, 则将e
作为原因拒绝promise
- 如果
then
是一个函数,用x
作为this
调用它,第一个参数resolvePromise
,第二个参数rejectPromise
,其中- 如果当
resolvePromise
的值为y
时,运行[[Resolve]](promise, y)
- 如果
rejectPromise
用一个原因r
调用,用r
拒绝promise
- 如果同时调用了
resolvePromise
和rejectPromise
,或者多次调用相同的参数,那么第一次调用优先,后续的调用将被忽略。(针对thenable
) - 如果调用
then
抛出一个异常e
- 如果
resolvePromise
或rejectPromise
已经被调用,忽略它。 - 否则用
e
作为原因拒绝promise
- 如果
- 如果当
- 如果
then
不是一个函数,用x
完成(resolve)promise
- 使
-
如果
x
不是一个对象或函数,用x
完成(resolve)promise
-
-
如果一个 promise
被 thenable
解析,并参与一个循环的 thenable
链,这样 [[Resolve]](promise, thenable)
的递归性质最终导致 [[Resolve]](promise, thenable)
再次被调用,按照上述算法将导致无限递归。我们鼓励(但不是必需)实现检测这种递归,并以 TypeError
作为原因拒绝承诺。[3.6]
-
注解
-
这里
平台代码
使引擎、环境以及promise的实现代码。在实践中,这需要确保onFulfilled
和onRejected
异步地执行,并且应该在then
方法被调用的那一轮事件循环之后用新的执行栈执行。这可以用如setTimeout
或setImmediate
这样的“宏任务”机制实现,或者用如MutationObserver
或process.nextTick
这样的“微任务”机制实现。由于promise
的实现被考虑为平台代码
,因此在自身处理程序被调用时可能已经包含一个任务调度队列 -
严格模式下,它们中的this将会是undefined;在非严格模式,this将会是全局对象
-
假如实现满足所有需求,可以允许
promise2 === promise1
。每一个实现都应该记录是否能够产生promise2 === promise1
以及什么情况下会出现promise2 === promise1
-
通常,只有
x
来自于当前实现,才知道它是一个真正的promise
。这条规则允许那些特例实现采用符合已知要求的Promise
的状态 -
这个程序首先存储
x.then
的引用,之后测试那个引用,然后再调用那个引用,这样避免了多次访问x.then
属性。此类预防措施对于确保访问者属性的一致性非常重要,因为访问者属性的值可能在俩次检索之间发生变化 -
实现不应该在
thenable
链的深度上做任意限制,并且假设超过那个任意限制将会无限递归。只有真正的循环才应该引发一个TypeError
;如果遇到一个无限循环的thenable
,永远执行递归是正确的行为
-
大纲图
代码实现
// 三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// 状态: 初始状态为 pending
status = PENDING
// 值
value = null
// 原因
reason = null
// 执行 onFulfilled 的队列
onFulfilledCallbacks = []
// 执行 onRejected 的队列
onRejectedCallbacks = []
// 构造方法
constructor(executor){
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
resolve = value => {
// 判断是否状态处于等待状态
if(this.status === PENDING){
// 改变状态
this.status = FULFILLED
// 赋值
this.value = value
// 循环调用
while(this.onFulfilledCallbacks.length){
this.onFulfilledCallbacks.shift()(this.value)
}
}
}
reject = reason => {
// 判断是否状态处于等待状态
if(this.status === PENDING){
// 更改状态
this.status = REJECTED
// 赋值原因
this.reason = reason
// 循环调用
while(this.onRejectedCallbacks.length){
this.onRejectedCallbacks.shift()(this.reason)
}
}
}
then(onFulfilled, onRejected){
// 可选参数
const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
const promise1 = new MyPromise((resolve, reject) => {
// 创建一个微任务执行完成的函数
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try{
let x = realOnFulfilled(this.value)
resolvePromise(promise1, x, resolve, reject)
}catch (error) {
reject(error)
}
})
}
// 创建一个微任务执行拒绝的函数
const rejectMicrotask = () => {
queueMicrotask(() => {
try{
let x = realOnRejected(this.reason)
resolvePromise(promise1, x, resolve, reject)
}catch (error) {
reject(error)
}
})
}
// 状态确定后直接执行
if(this.status == FULFILLED){
fulfilledMicrotask()
}else if(this.status == REJECTED){
rejectMicrotask()
}else{
// 异步,加入队列
this.onFulfilledCallbacks.push(fulfilledMicrotask)
this.onRejectedCallbacks.push(rejectMicrotask)
}
})
// then 返回一个新的 promise
return promise1
}
// catch 方法
catch (onRejected) {
this.then(null, onRejected)
}
}
function resolvePromise(promise, x, resolve, reject){
if(x === promise){
// 循环调用,直接报错
return reject(new TypeError('The promise and the return value are the same'));
}
if(typeof x === 'function' || typeof x === 'object'){
// null 直接返回
if(x === null) return resolve(x)
let then
try {
then = x.then
} catch (error) {
// 不存在直接拒绝
return reject(error)
}
// 如果对象上面存在 then 方法
if(typeof then === 'function'){
let called = false
try {
then.call(x, y => {
// 执行多次忽略
if(called) return
called = true
// 接着执行
resolvePromise(promise, y, resolve, reject)
}, r => {
// 执行多次忽略
if(called) return
called = true
reject(r)
})
} catch (error) {
//
if(called) return
called = true
reject(error)
}
}else{
// then 不是函数
resolve(x)
}
}else{
// 如果 x 不为对象或者函数,直接用 x 为参数执行 promise
resolve(x)
}
}
// 测试用
MyPromise.deferred = function(){
var result = {}
result.promise = new MyPromise(function(resolve, reject){
result.resolve = resolve
result.reject = reject
})
return result
}
module.exports = MyPromise
复制代码