前言
你可能经常使用 Promise
?但你知道你使用的 Promise
是怎么来的么?你知道 Promise
遵循什么规范吗?
Promise
的规范有很多,如Promise/A
,Promise/B
,Promise/D
以及 Promise/A
的升级版 Promise/A+
。ES6 中采用了 Promise/A+
规范。
所以我们今天就讲一讲 Promise/A+
规范。
任何符合 Promise
规范的对象或函数都可以成为 Promise
, 我们使用的 Promise
也不过是符合 Promise/A+
规范的其中一种形式,你也可以自己封装一个符合规范的函数,那么你写的函数也可以叫 Promise
。
术语
- Promise(实例): 是具有
then
方法的对象或函数,其行为符合此规范。 - thenable(具有then方法): 是一个定义
then
方法的对象或函数。 - value(值): 是任意合法的
Javascript
值,(包括 undefined
, thenable
, promise
)。 - exception(异常): 是使用
throw
语句抛出的值。 - reason(原因): 是表示
promise
为什么被 rejected
的原因,也就是要 throw
一个 error
。
要求
Promise的状态
一个 Promise
的当前状态必须为以下三种状态中的一种:等待态(Pending
)、已完成(Fulfilled
)和已拒绝(Rejected
)。
- 处于等待态时,
Promise
需满足以下条件:可以变成 已完成 或 已拒绝 。 - 处于已完成时,
Promise
需满足以下条件: - 不能迁移至其它任何状态
- 必须拥有一个 不可变 的值
- 处于已拒绝时,
Promise
需满足以下条件: - 不能迁移至其它任何状态
- 必须拥有一个 不可变 的原因
必须有一个then方法
一个 Promise
必须提供一个 then
方法以访问其当前值和原因。 也就是说当 Promise
的状态由 等待态 变为 已完成 或 已拒绝 时,得有一个地方注册回调函数。
-
Promise
的 then
方法接收 两个可选参数 ,Promise.then(onFulfilled, onRejected)
,两个参数必须是 函数,如果不是函数,则需要 忽略 它们。 - onFulfilled
- 当
Promise
执行结束后,onFulfilled
必须被调用,其第一个参数为 Promise
的值。 - 在
Promise
执行结束前,onFulfilled
不可被调用。 -
onFulfilled
的调用次数不可超过一次。 - onRejected
- 当
Promise
被拒绝执行后,onRejected
必须被调用,其第一个参数为 Promise
的原因。 - 在
Promise
被拒绝执行前,onRejected
不可被调用。 -
onRejected
的调用次数不可超过一次。 - 在执行上下文堆栈仅包含平台代码之前,不得调用
onFulfilled
和 onRejected
,这个跟 JavaScript
中的 Event Loop
相关,在当前的循环中,同步代码执行完之前不可以执行 onFulfilled
和 onRejected
这两个函数。 -
onFulfilled
和 onRejected
必须被作为普通函数调⽤(即⾮实例化调⽤(new Function
),这样函数内部 this
⾮严格模式下指向 window
)。 -
then
⽅法可以被同⼀个 Promise
调⽤多次: - 当
Promise
成功执⾏时,所有 onFulfilled
需按照其注册顺序依次回调。 - 当
Promise
被拒绝执⾏时,所有的onRejected
需按照其注册顺序依次回调。 -
then
⽅法必须返回⼀个 Promise
对象,promise2 = promise1.then(onFulfilled, onRejected)
- 只要
onFulfilled
或 onRejected
返回一个值 x
,promise2
都会进⼊ onFulfilled
状态。 - 如果
onFulfilled
或 onRejected
抛出一个异常 e
, 则 promise2
必须被拒绝执行并把 e
当作原因返回。 - 如果
onFulfilled
不是一个函数,并且 promise1
已经完成, promise2
必须成功执行并返回相同的值。 - 如果
onRejected
不是一个函数, 并且 promise1
已经被拒绝, promise2
必须执行拒绝回调并返回相同的拒因。 - 下面来看一个例子。
const promise1 = new Promise((resolve, reject) => reject())
// promise1 手动调用 reject 置为已拒绝状态 , 此时会执行第二个参数的回调函数. 返回 123.
promise1
// 根据只要 `onFulfilled` 或 `onRejected` 返回一个值 `x` ,`promise2` 都会进⼊ `onFulfilled` 状态 , 值为 123.
.then(null, () => {
return 123
})
//- 根据如果 `onFulfilled` 不是一个函数,并且 `promise1` 已经完成, `promise2` 必须成功执行并返回相同的值。 值依然为 123.
.then(null, null)
// 同上 值依然为 123.
.then(null, null)
// 根据如果 `onFulfilled` 不是一个函数,并且 `promise1` 已经完成, `promise2` 必须成功执行并返回相同的值。 打印 promise2 已完成,123
.then(
(res) => { console.log('promise2 已完成', res) }, //=> promise2 已完成 123
(res) => { console.log('promise2 已拒绝', res) }
)
Promise的解决过程
Promise
解决程序是一个抽象操作,我们将其表示为[[Resolve]](promise, x)
,它以一个 promise
和一个值作为输入。 (这句话的意思就是把 promise
的状态置为 resolve
,同时传入 x
作为值)。
promise.then((x) => { console.log('会执行这个函数,同时传入x变量的值', x); });复制代码
如果 x
有 then
方法且看上去像一个 Promise
, 解决程序就会尝试使 Promise
接受 x
的状态,否则就用 x
的值来执行 Promise
。
如果 Promise
和 x
都指向同一个对象
以 TypeError
为拒因拒绝执行 Promise
。这个没有实现,有大佬知道怎么回事的话,请评论区指教一下。
如果 x
为 Promise
,则使 Promise
接受 x
的状态 :
如果 x
处于等待态, Promise
需保持为等待态直至 x
被执行或拒绝。
const promise1 = new Promise((resolve, reject) => {
setInterval(() => {
resolve('已完成')
}, 3000)
})
const promise2 = new Promise((resolve, reject) => resolve(promise1))
promise2.then(
(val) => {
console.log(val); // 3000ms 后输出 已完成
},
(val) => {
console.log(val);
}
)
如果 x
处于已完成态,用相同的值执行 Promise
。
const promise1 = new Promise((resolve, reject) => resolve('已完成'))
const promise2 = new Promise((resolve, reject) => resolve(promise1))
promise2.then(
(val) => {
console.log(val); // 输出 已完成
},
(val) => {
console.log(val);
}
)
如果 x
处于已拒绝态,用相同的据因拒绝 Promise
。
const promise1 = new Promise((resolve, reject) => reject('已拒绝'))
const promise2 = new Promise((resolve, reject) => resolve(promise1))
promise2.then(
(val) => {
console.log(val);
},
(val) => {
console.log(val);// 输出 已拒绝
}
)
如果 x
为对象或者函数
1. 首先尝试执行 x.then
。
const promise = new Promise((resolve, reject) => resolve({
then: () => console.log('hello,promise') //=> hello,promise
}))
promise.then((x) => {
// 首先尝试执行 `x.then` ,输出 hello,promise 。
})
2. 如果取 x.then
的值时抛出错误 e
,则以 e
为据因拒绝 Promise
。
const promise = new Promise((resolve, reject) => resolve({
get then() {
throw Error("我要拒绝") // error
}
}))
promise.then(
(val) => {
console.log(val);
},
(val) => {
console.log(val); //=> error 我要拒绝
}
)
3.如果 then
不为函数,以 x
为参数将 Promise
变为已完成状态。
const promise = new Promise((resolve, reject) => resolve({
name: 'warbler'
}))
promise.then(
(val) => {
console.log(val.name); //=> warbler
},
(val) => {
console.log(val);
}
)
4. 如果 x.then
是函数,
将 x
作为函数的作用域 this
调用。传递两个回调函数作为参数,第一个参数叫做 resolvePromise
,第二个参数叫做 rejectPromise
。
4.1 如果 resolvePromise
以值 y
为参数被调用,则运行 [[Resolve]](promise, y)
const promise = new Promise((resolve, reject) => resolve({
then: (resolvePromise, rejectPromise) => {
resolvePromise('已完成')
}
}))
promise.then(
(val) => {
console.log(val); //=> 已完成
},
(val) => {
console.log(val);
}
)
4.2 如果 rejectPromise
以据因 r
为参数被调用,则以据因 r
拒绝 promise
const promise = new Promise((resolve, reject) => resolve({
then: (resolvePromise, rejectPromise) => {
rejectPromise('已拒绝')
}
}))
promise.then(
(val) => {
console.log(val);
},
(val) => {
console.log(val); //=> 已拒绝
}
)
4.3 如果 resolvePromise
和 rejectPromise
均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
const promise1 = new Promise((resolve, reject) => resolve({
then: (resolvePromise, rejectPromise) => {
resolvePromise('已完成') // 生效
resolvePromise('已完成') // 忽略
rejectPromise('已拒绝') // 忽略
}
}))
promise1.then(
(val) => {
console.log(val); //=> 已完成
},
(val) => {
console.log(val);
}
)
4.4 如果调用 then
方法抛出了异常 e
:
如果 resolvePromise
或 rejectPromise
已经被调用,则忽略。
const promise = new Promise((resolve, reject) => resolve({
then: (resolvePromise, rejectPromise) => {
resolvePromise('已完成')
throw new Error("我要拒绝") // 忽略
}
}))
promise.then(
(val) => {
console.log(val); //=> 已完成
},
(val) => {
console.log(val);
}
)
否则以 e
为据因拒绝 promise
。
const promise = new Promise((resolve, reject) => resolve({
then: (resolvePromise, rejectPromise) => {
throw new Error("我要拒绝")
}
}))
promise.then(
(val) => {
console.log(val);
},
(val) => {
console.log(val); //=> error 我要拒绝
}
)
如果 x
不为对象或者函数,以 x
为参数将 Promise
变为已完成状态。
const promise = new Promise((resolve, reject) => resolve('warbler'))
promise.then(
(val) => {
console.log(val); //=> warbler
},
(val) => {
console.log(val);
}
)
后语
到这里 Promise/A+
规范就解析完了,后面的任务就是手写 Promise
了。