Promise/A+规范
规范规定了几个重要信息:
-
promise是一个状态机
-
promise 必须提供一个
then
方法来处理其最终返回的值或出错的原因,**then**
方法拥有两个参数:**promise.then(onFulfilled, onRejected)**
,其中:onFulfilled
和onRejected
都是可选参数, 如果不是函数,必须被忽略- 当
onFulfilled
是一个函数- 必须在promise的状态转为 fulfilled 后被执行,并且将promise的value作为第一个参数
- 只能被执行一次
- 当
onRejected
是一个函数- 必须在promise的状态转为 rejected 后被执行,并且将promise的value作为第一个参数
- 只能被执行一次
- 在执行上下文堆栈仅包含平台代码之前,不得调用onFulfilled或onRejected。(不太理解这段,大概是支持异步吧?)
then
可以被执行多次,当promise的状态转为fulfilled/rejected 后,**onFulfilled
** 和**onRejected
** 会按原来被绑定的顺序被执行。then
必须返回一个promisepromise2 = promise1.then(onFulfilled, onRejected)
- 当 onFulfilled或onRejected 返回一个值x,运行promise解析程序
[[Resolve]](promise2,x)
- 当 onFulfilled或onRejected 抛出异常e,promise2必须转为rejected,并把e作为reason
- 当
**onFulfilled
** 不是函数,并且promise1的状态为fulfilled, promise2 必须以相同的value值完成状态转换。 - 当
**onRejected
** 不是函数,并且promise1的状态为rejected, promise2 必须以相同的reason完成状态转换。
- 当 onFulfilled或onRejected 返回一个值x,运行promise解析程序
-
[[Resolve]](promise2,x
promise解析程序Promise解析过程是一个抽象操作,将Promise和一个值作为输入,我们将其表示为
[[Resolve]](promise,x)
。总体而言,如果x是thenable,也就是包含了then方法,会在x至少表现得像Promise的假设下,令promise采纳x的状态。否则,promise将以值 x fulfill。执行的细节按照如下步骤
- 如果 x 和 promise指向同一个对象,则以
TypeError
作为原因reject promise - 如果 x 是 promise,采纳其状态
- 如果 x 是 object 或 function
- let then = x.then
- 如果检索属性x.then导致抛出异常e,请拒绝promise,原因为e。
- 如果then是一个函数,则使用x作为this调用,第一个参数resolvePromise,第二个参数rejectPromise
- 如果使用值 y 调用resolvePromise时,运行**
[[Resolve]](promise,y)
** - 如果使用原因r调用rejectPromise时,使用r拒绝promise
- 如果同时调用resolvePromise和rejectPromise,或者对同一参数进行了多次调用,则第一个调用具有优先权,而任何其他调用都将被忽略。
- 如果 then 调用发生异常
- 如果已调用resolvePromise或rejectPromise,忽略异常
- 否则,以e为理由拒绝promise。
- 如果使用值 y 调用resolvePromise时,运行**
- 如果 x 和 promise指向同一个对象,则以
清楚了PromiseA+规范,下面开始一步一步地实现。
实现框架
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,因此这里我们首先写出构造函数骨架。其中 resolve和reject是需要内部实现的部分, resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)。
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Mypromise {
constructor(executor) {
this.value = null;
this.reason = null;
this.state = PENDING;
const resolve = (value) => {
this.value = value
this.state = FULFILLED
}
const reject = (reason) => {
this.reason = reason
this.state = REJECTED
}
try {
executor(resolve, reject)
}catch (reason){
reject(reason)
}
}
}
实现then方法
then 方法接受两个函数,实现延时绑定的功能,并能支持多次调用,因此我们需要在内部用两个数组保存相应的回调函数,从而,在执行resolve和reject时,只需要从相应数组中取出回调函数依次执行。
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Mypromise {
constructor(executor) {
this.value = null;
this.reason = null;
this.state = PENDING;
this.onFullfilledCallbacks = []; // 保存成功的回调
this.onRejectedCallbacks = []; // 保存失败的回调
const resolve = (value) => {
this.value = value
this.state = FULFILLED
// 从成功的回调数组中取出回调函数依次执行。
this.onFullfilledCallbacks.forEach(onFullfilledCallback => {
onFullfilledCallback(this.value)
})
}
const reject = (reason) => {
this.reason = reason
this.state = REJECTED
// 从失败的回调数组中取出回调函数依次执行
this.onRejectedCallbacks.forEach(onRejectedCallback => {
onRejectedCallback(this.reason)
})
}
try {
executor(resolve, reject)
}catch (reason){
reject(reason)
}
}
then(onFulfilled, onRejected) {
if (this.state === FULFILLED) {
onFulfilled(this.value)
}else if (this.state === REJECTED) {
onRejected(this.reason)
}else {
this.onFullfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
}
以上构造方法保证了回调函数的延时绑定,并且确保了按绑定顺序使用回调函数。所有的promise都是一样的,不同的就是executor
这个立即执行的函数所决定的resolve或reject的时机。因此,下面then方法返回新promise2也是这个思路,让新promise2的executor
和当前的promise强相关。
then方法返回一个promise
then(onFulfilled, onRejected) {
console.log('then called')
const promise2 = new MyPromise((resolve, reject) => {
// 如果当前promise状态还是pending,封装回调函数进数组,
// 等到promise状态转换后,自然会调用相应的回调函数,之后收集返回值开始解析promise2
if (this.state === PENDING) {
this.onFullfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch(error) {
reject(error);
}
})
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}catch(error) {
reject(error)
}
})
}
else if (this.state === FULFILLED) {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch (error) {
reject(error)
}
}
else if (this.state === REJECTED) {
try {
let x = onRejected(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch (error) {
reject(error)
}
}
})
return promise2;
}
Promise解析函数
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Chaining Cycle'));
}
if (x && typeof x === 'object' || typeof x === 'function') {
let used;
try {
let then = x.then;
// x.then 是 function 说明 x 是promise
if (typeof then === 'function') {
then.call(x, (y) => {
if (used) return;
used = true;
this.resolvePromise(promise2, y, resolve, reject)
}, (r) => {
if (used) return;
used = true;
reject(r);
})
} else {
if (used) return;
used = true;
resolve(x);
}
}catch (error) {
if (used) return;
used = true
reject(error)
}
} else {
resolve(x);
}
}
完整代码示例
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise {
constructor(executor) {
this.PID = Math.random(); // 没用,方便调试的时候查看
this.value = null
this.reason = null
this.state = PENDING;
this.onFullfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
this.value = value
this.state = FULFILLED
this.onFullfilledCallbacks.forEach(onFullfilledCallback => {
onFullfilledCallback(this.value)
})
console.log('Promise state is ' + this.state)
}
const reject = (reason) => {
this.reason = reason
this.state = REJECTED
this.onRejectedCallbacks.forEach(onRejectedCallback => {
onRejectedCallback(this.reason)
})
console.log('Promise state is ' + this.state)
}
try {
executor(resolve, reject)
}catch (reason){
this.reject(reason)
}
}
then(onFulfilled, onRejected) {
console.log('then called')
const promise2 = new MyPromise((resolve, reject) => {
// 如果当前promise状态还是pending,封装回调函数进数组,等到promise状态转换后,自然会
// 调用相应的回调函数,并开始解析promise2
if (this.state === PENDING) {
this.onFullfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch(error) {
reject(error);
}
})
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}catch(error) {
reject(error)
}
})
}
else if (this.state === FULFILLED) {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch (error) {
reject(error)
}
}
else if (this.state === REJECTED) {
try {
let x = onRejected(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch (error) {
reject(error)
}
}
})
return promise2;
}
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Chaining Cycle'));
}
if (x && typeof x === 'object' || typeof x === 'function') {
let used;
try {
let then = x.then;
// x.then 是 function 说明 x 是promise
if (typeof then === 'function') {
then.call(x, (y) => {
if (used) return;
used = true;
this.resolvePromise(promise2, y, resolve, reject)
}, (r) => {
if (used) return;
used = true;
reject(r);
})
} else {
if (used) return;
used = true;
resolve(x);
}
}catch (error) {
// 如果已调用resolvePromise或rejectPromise,忽略异常
if (used) return;
used = true
reject(error)
}
} else {
resolve(x);
}
}
// 最后的catch, 只传onRejected即可
catch(onRejected) {
return this.then(null, onRejected);
}
}