手把手带你实现符合Promise/A+规范的Promise

  • Post author:
  • Post category:其他




手把手带你实现符合Promise/A+规范的Promise

如果你还没有使用Promise的经验,那我建议你先阅读博主之前关于

《带你快速入门ES6中的Promise对象》

的文章。

本篇博文主要带领大家一步步实现Promise/A+规范的Promise,所以前提是你需要对Promise有一定的基础,然后通过一步步实现自己的Promise,才能更加深入的了解到Promise底层的实现原理。



什么是Promise/A+规范?

首先什么是Promise/A+规范?官网上是这么描述的:

An open standard for sound, interoperable JavaScript promises—by implementers, for implementers.

简而言之它是一套标准,ES中标准的Promise实现就是遵守这一套标准的。当然还有其他的Promise库,他们也是遵守这一套标准的。所以这套标准告诉我们一个规范的Promise需要满足哪些条件。具体的条件可以在官网中获取,这里就不多赘述了。官网链接:

https://promisesaplus.com/



一步步实现自定义Promise

我们自己实现的自定义Promise首先肯定是符合Promise/A+规范的,然后我们会参考ES6的Promise进行对比来一步步实现自己的Promise。



构造函数

首先我们来看规范中怎么定义一个Promise

“promise” is an object or function with a then method whose behavior conforms to this specification.

然后我们来看,ES6中是怎么创建一个Promise的?

let promise = new Promise(function(resolve, reject) {
  /*
    如果操作成功,调用resolve并传入value   --> resolve(value)
    如果操作失败,调用reject并传入reason   --> rejectreason)
  */
})

可以看到ES6中是通过new一个Promise,然后传入一个方法,方法有两个参数

(resolve, reject)

,当异步操作成功,调用

resolve

,异步操作失败调用

reject

。 所以这两个参数实际上是两个方法,并确实带一个参数的方法。

然后在定义中还说了,一个promise是需要带一个

then

方法的,我们可以看看ES6中的

then

方法

在这里插入图片描述

这个

then

方法接受两个参数:

promise.then(onFulfilled, onRejected)

接下来我们可以模仿着,写一下我们自定义Promise的

构造函数



then

方法

function Promise(executor){ //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数

}

Promise.prototype.then = function (onFulfilled, onRejected){

}



resolve 与 reject的构建与基础实现

如果你有一定的基础,你就知道Promise是有三种状态的pending, fulfilled, rejected

可以看规范中对Promise states的定义:

A promise must be in one of three states: pending, fulfilled, or rejected.

  • 2.1.1. When pending, a promise:

    • 2.1.1.1. may transition to either the fulfilled or rejected state.
  • 2.1.2. When fulfilled, a promise:

    • 2.1.2.1. must not transition to any other state.
    • 2.1.2.2. must have a value, which must not change.
  • 2.1.3. When rejected, a promise:

    • 2.1.3.1. must not transition to any other state.
    • 2.1.3.2. must have a reason, which must not change.

然后我们看到ES6中的Promise对象上是会有一个

PromiseState

的属性的,这个属性只有三种状态

pending, fulfilled, rejected

在这里插入图片描述

而且当一个Promise实例化出来的时候,状态是

pending

,然后通过调用

resolve

方法或者

reject

方法去改变Promise的状态。

所以我们需要我们自定义的Promise加一个属性,然后默认初始化的时候是

pending

function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = 'pending';
}

Promise.prototype.then = function (onFulfilled, onRejected) {

}

然后我们继续来完善一些细节,首先我们看到ES6的Promise中还有一个属性就是

PromiseResult

,他是用来存储这个Promise的值,默认是

undefined

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
}

Promise.prototype.then = function (onFulfilled, onRejected) {

}

然后还有几个细节就是,Promise在实例化完成之后就会立马执行,比如ES6中的Promise

在这里插入图片描述

所以我们在Promise的构造函数中需要调用,传进来的

executor

方法。但是这个

executor

方法还有两个参数

resolve,reject

,我们需要给他传进去,所以我们还需要定义一下这两个方法。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined

    //resolve 函数
    function resolve(data) {
       
    }
    //reject 函数
    function reject(data) {
       
    }

    //同步调用『执行器函数』
    executor(resolve, reject)

}

Promise.prototype.then = function (onFulfilled, onRejected) {

}

接下来,我们需要去实现

resolve

方法和

reject

方法。

首先我们知道在ES6的Promise中,可以通过

resolve

方法把Promise从

pending

变成

fulfilled

; 可以通过通过

reject

方法把Promise从

pending

变成

rejected

, 并且传入方法的参数,最后会变成Promise的

PromiseResult

属性的值。如下:

在这里插入图片描述

所以接下来我们就可以实现

resolve

方法和

reject

方法了。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED; // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }
    //reject 函数
    function reject(data) {
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED; // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }

    //同步调用『执行器函数』
    executor(resolve, reject)

}

Promise.prototype.then = function (onFulfilled, onRejected) {

}

接下来我们可以测试一下实例化Promise对象的时候有没有问题了,我们写这样的一段测试代码,来看看控制台的输出。

 let p1 = new Promise((resolve, reject) => {
    console.log("同步执行1")
    resolve('success')
})
let p2 = new Promise((resolve, reject) => {
    console.log("同步执行2")
    reject('failed')
})
console.log("同步执行3")
console.log(p1)
console.log(p2)

在这里插入图片描述



throw 抛出异常改变状态

我们在学习promise的时候也知道,当在promise中的异步操作发生异常的时候,最后的状态会变成

rejected

,而且最后的

PromiseResult

的值,是我们抛出的这个异常对象。但我们现在的代码很明显没有这一步的操作。

下面是ES6中Promise的执行结果:

在这里插入图片描述

接下来我们就来处理这一步,所以我们需要捕获

executor(resolve, reject)

执行的异常,然后把当前的状态变成

rejected

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED; // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }
    //reject 函数
    function reject(data) {
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED; // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {

}

接下来我们来测试这一部分的功能

let p3 = new Promise((resolve, reject) => {
    throw new Error('error!');
})

控制台输出如下:

在这里插入图片描述



Promise的状态一旦改变,就不会再变

一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从

pending

变为

fulfilled

和从

pending

变为

rejected

比如在ES6中执行如下代码,可以看出来,一旦Promise的状态改变了,就不会在变了

在这里插入图片描述

但是我们现在的实现中没有做这样的限制,所以现在我们需要加上这个逻辑,也就是只有在

pending

状态下,才能变为

fulfilled

或者

rejected

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED; // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED; // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {

}



then 方法执行回调基础实现

promise的

then(onFulfilled, onRejected)

方法当promise的状态是

fulfilled

的时候就会调用

onFulfilled

方法,当状态是

rejected

的时候就会调用

onRejected

方法,并且会把

PromiseResult

的结果传入。

所以下面我们需要实现

then

方法

Promise.prototype.then = function (onFulfilled, onRejected) {
    //调用回调函数  PromiseState
    if (this.PromiseState === FULFILLED) {
        onFulfilled(this.PromiseResult)
    }
    if (this.PromiseState === REJECTED) {
        onRejected(this.PromiseResult)
    }
}

我们可以进行测试看看

let p1 = new Promise((resolve, reject) => {
    resolve('success')
})
p1.then(function (resolved) { 
    console.log(resolved)
}, function (rejected) { 
    console.log(rejected)
})

let p2 = new Promise((resolve, reject) => {
    reject('failed')
})
p2.then(function (resolved) { 
    console.log(resolved)
}, function (rejected) { 
    console.log(rejected)
})

在这里插入图片描述

但上面的方法存在一个问题,就是当promise里面的操作是异步执行之后才进行

resolve

方法或者

reject

方法的话,在执行

then

就会有问题,因为这个时候

PromiseState

的状态还是

pending

我们可以测试看看

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('success'), 0) // resolve方法会异步执行,所以会先执行下面的then方法,此时当前的状态是pending
})
p1.then(function (resolved) { //then方法执行,判断当前状态,因为当前状态是pending,所以不会进行任何操作
    console.log(resolved)
}, function (rejected) {
    console.log(rejected)
})

结果就是控制台没有输出

但是如果是在ES6下,输出的结果是什么呢,我们可以看看是能够正常输出的

在这里插入图片描述

所以我们下面需要来解决一下这个异步的问题



异步任务 then 方法实现

我们现在的问题就是,如果promise里面是同步改变promise的状态,那么后面在进行

then

方法的时候就能够拿到promise改变的状态;但是如果promise里面是异步改变的话,就需要等promise改变状态之后,才会执行

then

的回调

那么怎么实现,等promise的状态发生改变之后,才会执行

then

的回调呢?

其实也就是当我们在执行

resolve

方法或者

reject

方法的时候,我们需要去调用

then

的回调。那很显然我们就需要保存

then

的回调,不然当

then

方法执行完之后,我们就没法再次获取到回调的内容。所以我们在

then

方法中就需要把我们的回调保存起来。

所以我们需要在promise中新增一个属性,用来存储

then

方法的回调,然后在

then

方法执行的时候,如果当前的状态是

pending

的话,就把回调保存起来,当以后状态从

pending

变成其他状态的时候,就可以把回调方法拿出来执行了。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callback = {};	 //保存then方法的回调
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED; // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用成功的回调函数  加判断的原因是防止无回调报错
        if (self.callback.onFulfilled) {
            self.callback.onFulfilled(self.PromiseResult);
        }
    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED; // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用失败的回调函数  加判断的原因是防止无回调报错
        if (self.callback.onRejected) {
            self.callback.onRejected(self.PromiseResult);
        }
    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {
    // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
    if (this.PromiseState === PENDING) {
        this.callback = {
            onFulfilled,
            onRejected
        }
    }
    //如果状态是成功或者失败的话,就直接执行回调方法
    if (this.PromiseState === FULFILLED) {
        onFulfilled(this.PromiseResult)
    }
    if (this.PromiseState === REJECTED) {
        onRejected(this.PromiseResult)
    }
}

然后我们在进行之前的测试,就可以发现能够正常输出了

在这里插入图片描述



根据Promise/A+规范 优化then方法

在规范中,对

then

方法有下面这一段描述

  • 2.2.1. Both onFulfilled and onRejected are optional arguments:

    • 2.2.1.1. If onFulfilled is not a function, it must be ignored.
    • 2.2.1.2. If onRejected is not a function, it must be ignored.
  • 2.2.2. If onFulfilled is a function:

    • 2.2.2.1. it must be called after promise is fulfilled, with promise’s value as its first argument.
    • 2.2.2.2. it must not be called before promise is fulfilled.
    • 2.2.2.3. it must not be called more than once.
  • 2.2.3. If onRejected is a function,

    • 2.2.3.1. it must be called after promise is rejected, with promise’s reason as its first argument.
    • 2.2.3.2. it must not be called before promise is rejected.
    • 2.2.3.3. it must not be called more than once.

上面的大部分我们已经实现了,但是还是有一些细节还没有实现,关于

2.2.1

这部分规范我们需要优化一下

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callback = {};	 //保存then方法的回调
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED; // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用成功的回调函数  加判断的原因是防止无回调报错
        if (self.callback.onFulfilled) {
            self.callback.onFulfilled(self.PromiseResult);
        }
    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return;
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED; // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用失败的回调函数  加判断的原因是防止无回调报错
        if (self.callback.onRejected) {
            self.callback.onRejected(self.PromiseResult);
        }
    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {

    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (v) { }
    onRejected = typeof onRejected === 'function' ? onRejected : function (r) { }

    // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
    if (this.PromiseState === PENDING) {
        this.callback = {
            onFulfilled,
            onRejected
        }
    }
    //如果状态是成功或者失败的话,就直接执行回调方法
    if (this.PromiseState === FULFILLED) {
        onFulfilled(this.PromiseResult)
    }
    if (this.PromiseState === REJECTED) {
        onRejected(this.PromiseResult)
    }
}



指定多个回调

我们可以从Promise/A+ 规范中可以看到同一个promise是可以指定多个

then

的回调的

  • 2.2.6. then may be called multiple times on the same promise.

    • 2.2.6.1. If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
    • 2.2.6.2. If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.

比如在ES6的Promise中如下:

在这里插入图片描述

然而我们现在的代码是不支持的,因为我们现在保存的回调只有一个,所以后面执行

then

方法保存的回调就会覆盖前面保存的回调。

所以显而易见,我们需要把我们的promise里面保存回调的属性,改成一个列表,我们需要存储一个回调的列表,等promise的状态发生变化的时候,就把这个回调列表都拿出来执行。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callbacks = []	 //保存then方法的回调,这里保存的可能是多个回调,所以需要用列表来保存
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用成功的回调函数  加判断的原因是防止无回调报错
            if (callback.onFulfilled) {
                callback.onFulfilled(self.PromiseResult)
            }
        })

    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用失败的回调函数  加判断的原因是防止无回调报错
            if (callback.onRejected) {
                callback.onRejected(self.PromiseResult)
            }
        })

    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {

    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (v) { }
    onRejected = typeof onRejected === 'function' ? onRejected : function (r) { }

    // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
    if (this.PromiseState === PENDING) {
        this.callbacks.push({
            onFulfilled,
            onRejected
        })
    }
    //如果状态是成功或者失败的话,就直接执行回调方法
    if (this.PromiseState === FULFILLED) {
        onFulfilled(this.PromiseResult)
    }
    if (this.PromiseState === REJECTED) {
        onRejected(this.PromiseResult)
    }
}

好,接下来用我们自己写的promise试试看

在这里插入图片描述



then 返回结果是一个新的promise对象

规范里说到,then方法返回的是一个新的promise对象

  • 2.2.7. then must return a promise.

    • promise2 = promise1.then(onFulfilled, onRejected);

所以接下来我们需要对我们的代码进行改造,在then方法中,最后

return new Promise

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callbacks = []	 //保存then方法的回调,这里保存的可能是多个回调,所以需要用列表来保存
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用成功的回调函数  加判断的原因是防止无回调报错
            if (callback.onFulfilled) {
                callback.onFulfilled(self.PromiseResult)
            }
        })

    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用失败的回调函数  加判断的原因是防止无回调报错
            if (callback.onRejected) {
                callback.onRejected(self.PromiseResult)
            }
        })

    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {

    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (v) { }
    onRejected = typeof onRejected === 'function' ? onRejected : function (r) { }
    return new Promise((resolve, reject) => { // then 返回的是一个新的promise对象 / 2.2.7. then must return a promise.
        // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
        if (this.PromiseState === PENDING) {
            this.callbacks.push({
                onFulfilled,
                onRejected
            })
        }
        //如果状态是成功或者失败的话,就直接执行回调方法
        if (this.PromiseState === FULFILLED) {
            onFulfilled(this.PromiseResult)
        }
        if (this.PromiseState === REJECTED) {
            onRejected(this.PromiseResult)
        }
    })
}

接下来我们可以测试看看。

在这里插入图片描述

结果可以发现,虽然then方法返回的确实是一个新的promise对象,但是这个promise对象的状态是

pending

,而且promise的值是

undefined

,这是因为我们没有调用

resolve

或者

reject

方法去改变promise的状态。

所以下面我们需要处理

then(onFulfilled, onRejected)

返回promise的状态和值的问题。

那我们来看看规范是怎么描述的

  • 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
  • 2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
  • 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
  • 2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

先看后面的描述,大概意思就是,当

then(onFulfilled, onRejected)

中,如果回调方法

onFulfilled, onRejected

中如果抛出异常,那么返回的新的promise状态是

rejectd

,并且promise的值就是抛出的异常error。

然后如果

then(onFulfilled, onRejected)

中的

onFulfilled, onRejected

都不是一个方法,那么返回的新promise的状态,跟调用then方法的promise对象是同一个状态和同一个值,我们可以看看ES6中promise的情况

在这里插入图片描述

在这里插入图片描述

最后我们再来看第一条规范,如果

then(onFulfilled, onRejected)

中的回调方法

onFulfilled, onRejected

是一个方法,并且会有一个返回值

x

,那么接下来就会调用

Promise Resolution Procedure [[Resolve]](promise2, x)

方法,传入当前新的promise对象和

onFulfilled, onRejected

返回的值

x

。 这个

Promise Resolution Procedure [[Resolve]](promise2, x)

方法里面的具体逻辑我们后面再来处理。

还有一点需要值得注意的就是

then

方法中的回调方法是异步执行的,我们现在

then

方法中的回调是同步执行的,而且如果是同步在后续的开发中你就会发现会报一个错:

ReferenceError: Cannot access 'promise2' before initialization

,所以这点还需要改造一下。

所以我们开始接下来的改造

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callbacks = []	 //保存then方法的回调,这里保存的可能是多个回调,所以需要用列表来保存
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用成功的回调函数  加判断的原因是防止无回调报错
            if (callback.onFulfilled) {
                callback.onFulfilled(self.PromiseResult)
            }
        })

    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用失败的回调函数  加判断的原因是防止无回调报错
            if (callback.onRejected) {
                callback.onRejected(self.PromiseResult)
            }
        })

    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {


    // the Promise Resolution Procedure [[Resolve]](promise2, x)
    function resolvePromise(promise2, x, resolve, reject) {

    }


    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    //2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
    //2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => {throw reason}
    const promise2 = new Promise((resolve, reject) => { // then 返回的是一个新的promise对象 / 2.2.7. then must return a promise.
        // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
        if (this.PromiseState === PENDING) {
            this.callbacks.push({
                onFulfilled: function (value) {
                  setTimeout(() => { // then方法中的回调是异步执行的
                    try {
                        // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        resolvePromise(promise2, onFulfilled(value), resolve, reject)
                    } catch (error) {
                        //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                        reject(error)
                    }
                  })
                },
                onRejected: function (reason) {
                 setTimeout(() => { // then方法中的回调是异步执行的
                    try {
                        // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        resolvePromise(promise2, onRejected(reason), resolve, reject)
                    } catch (error) {
                        //2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                        reject(error)
                    }
                  })
                }
            })
        }
        //如果状态是成功或者失败的话,就直接执行回调方法
        if (this.PromiseState === FULFILLED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onFulfilled(this.PromiseResult), resolve, reject)
                } catch (error) {
                    //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })


        }
        if (this.PromiseState === REJECTED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onRejected(this.PromiseResult), resolve, reject)
                } catch (error) {
                    // 2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })
        }
    })
    return promise2
}

接下来我们就需要实现

The Promise Resolution Procedure

方法中的具体逻辑了,也就是我们上面代码中的

resolvePromise

方法



The Promise Resolution Procedure

我们来看规范中对

The Promise Resolution Procedure

方法的定义

  • 2.3.1 If promise and x refer to the same object, reject promise with a TypeError as the reason.
  • 2.3.2 If x is a promise, adopt its state [3.4]:

    • 2.3.2.1 If x is pending, promise must remain pending until x is fulfilled or rejected.
    • 2.3.2.2 If/when x is fulfilled, fulfill promise with the same value.
    • 2.3.2.3 If/when x is rejected, reject promise with the same reason.
  • 2.3.3 Otherwise, if x is an object or function,

    • 2.3.3.1 Let then be x.then. [3.5]
    • 2.3.3.2 If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
    • 2.3.3.3 If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:

      • 2.3.3.3.1 If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
      • 2.3.3.3.2 If/when rejectPromise is called with a reason r, reject promise with r.
      • 2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
      • 2.3.3.3.4 If calling then throws an exception e,

        • 2.3.3.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.
        • 2.3.3.3.4.2 Otherwise, reject promise with e as the reason.
    • 2.3.3.4 If then is not a function, fulfill promise with x.

首先来看

2.3.1

这个怎么理解呢,其实就是then方法新返回的promise对象,不能跟then方法返回的值是同一个对象。这里我们可以看看ES6中的promise

在这里插入图片描述

可以看到上面代码中

p1.then

方法中回调方法返回的值,刚好就是这个

then

方法返回的新promise对象,这个时候就会报一个

TypeError

后面的规范可以总结为以下几点:

  1. 如果

    then

    方法的回调方法返回的

    x

    是promise对象,那么

    then

    方法返回的promise对象的状态跟

    x

    是一样的,并且值也是一样的。如果

    x

    的状态是

    pending

    ,那么新返回的promise对象就会等到

    x

    的状态变成

    fulfilled

    或者

    rejected
  2. 如果

    then

    方法的回调方法返回的

    x

    是一个thenable对象。比如下面这种
let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

那么就会就立即执行thenable对象的

then()

方法,如果thenable对象的

then()

方法最后如果是调用了

resolve

方法,那么最后返回新的promise就是

fulfilled

,如果thenable对象的

then()

方法最后如果是调用了

reject

方法,那么最后返回新的promise就是

rejected

。如果thenable对象的

then()

方法执行过程中抛出异常,那么最后返回新的promise就是

rejected

。 注意这里如果thenable对象的

then()

方法一旦调用了

resolve

方法或者

reject

方法或者抛出了异常之后状态就不会变了,后续调用多次

resolve

方法或者

reject

方法都不会改变结果。

我们可以看看ES6中的promise

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 如果

    then

    方法的回调方法返回的

    x

    对象,如果

    x

    对象有

    then

    属性,但是不是一个方法的话,返回的是一个

    fulfilled

    的promise。比如ES6中的promise

在这里插入图片描述

  1. 如果

    then

    方法的回调方法返回的

    x

    是不是一个对象或者不是一个方法,也是返回的是一个

    fulfilled

    的promise,比如ES6中的promise

在这里插入图片描述

接下来我们就来实现上面的规范。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    if (typeof executor !== 'function') {
        throw new TypeError(`Promise resolver ${executor} is not a function`)
    }

    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callbacks = []	 //保存then方法的回调,这里保存的可能是多个回调,所以需要用列表来保存
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用成功的回调函数  加判断的原因是防止无回调报错
            if (callback.onFulfilled) {
                callback.onFulfilled(self.PromiseResult)
            }
        })

    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用失败的回调函数  加判断的原因是防止无回调报错
            if (callback.onRejected) {
                callback.onRejected(self.PromiseResult)
            }
        })

    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {


    // the Promise Resolution Procedure [[Resolve]](promise2, x)
    function resolvePromise(promise2, x, resolve, reject) {

        // 2.3.1 If promise and x refer to the same object, reject promise with a TypeError as the reason.
        if (promise2 === x) {
            // 防止进入死循环
            reject(new TypeError("Chaining cycle detected for promise"))
        }

        if (x instanceof Promise) {
            // 2.3.2 If x is a promise
            // 判断如果是promise的话,则采用他的最终结果
            x.then(
                value => {
                    resolvePromise(promise2, value, resolve, reject)
                },
                reason => {
                    reject(reason)
                }
            )
        } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
            // 2.3.3 Otherwise, if x is an object or function
            let called = false
            try {
                // 2.3.3.1 Let then be x.then
                // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason
                //  const then = x.then 包裹在try...catch..中
                const then = x.then
                //  If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromis
                if (typeof then === "function") {
                    // 2.3.3.3.1 If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
                    // 2.3.3.3.2 If/when rejectPromise is called with a reason r, reject promise with r.
                    // 2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
                    // 如果then是一个函数,则用x调用它;第一个参数是 resolvePromise,第二个参数是 rejectPromise
                    // 如果同时调用 resolvePromise 和 rejectPromise,或者多次调用同一个参数,则第一个调用具有优先权,后续的调用将被忽略。(所以需要使用 called 进行控制)
                    then.call(x, (y) => {
                        if (called) {
                            return
                        }
                        called = true
                        resolvePromise(promise2, y, resolve, reject)
                    }, (reason) => {
                        if (called) {
                            return
                        }
                        called = true
                        reject(reason)
                    })
                } else {
                    resolve(x)
                }
            } catch (error) {
                // 2.3.3.3.4 If calling then throws an exception e,
                // 2.3.3.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.
                // 2.3.3.3.4.2 Otherwise, reject promise with e as the reason.
                if (called) {
                    return
                }
                called = true
                reject(error)
            }
        } else {
            resolve(x)
        }
    }


    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    //2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
    //2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason }
    const promise2 = new Promise((resolve, reject) => { // then 返回的是一个新的promise对象 / 2.2.7. then must return a promise.
        // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
        if (this.PromiseState === PENDING) {
            this.callbacks.push({
                onFulfilled: function (value) {
                    setTimeout(() => {
                        try {
                            // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            resolvePromise(promise2, onFulfilled(value), resolve, reject)
                        } catch (error) {
                            //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                            reject(error)
                        }
                    })
                },
                onRejected: (reason) => {
                    setTimeout(() => {
                        try {
                            // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            resolvePromise(promise2, onRejected(reason), resolve, reject)
                        } catch (error) {
                            //2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                            reject(error)
                        }
                    })
                }
            })
        }
        //如果状态是成功或者失败的话,就直接执行回调方法
        if (this.PromiseState === FULFILLED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onFulfilled(this.PromiseResult), resolve, reject)
                } catch (error) {
                    //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })


        }
        if (this.PromiseState === REJECTED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onRejected(this.PromiseResult), resolve, reject)
                } catch (error) {
                    // 2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })
        }
    })
    return promise2
}

最后我们可以通过

promises-aplus-tests

工具来进行测试

首先需要安装

promises-aplus-tests

npm i promises-aplus-tests -D

然后还需要在你的代码最后加上下面这段代码

Promise.defer = Promise.deferred = function() {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
  dfd.resolve = resolve
  dfd.reject = reject
})
return dfd
}

所以整个

test-promise.js

文件的内容如下:

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) { //构造函数传入一个方法,方法有两个参数,两个参数都是一个方法并且带一个传入参数
    if (typeof executor !== 'function') {
        throw new TypeError(`Promise resolver ${executor} is not a function`)
    }

    //添加属性
    this.PromiseState = PENDING
    this.PromiseResult = undefined
    this.callbacks = []	 //保存then方法的回调,这里保存的可能是多个回调,所以需要用列表来保存
    //保存实例对象的 this 的值
    //此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window
    const self = this
    //resolve 函数
    function resolve(data) {
        if (self.PromiseState !== PENDING) {   //判断状态,保证promise的状态只能从'pending'变为'fulfilled'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = FULFILLED // fulfilled
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用成功的回调函数  加判断的原因是防止无回调报错
            if (callback.onFulfilled) {
                callback.onFulfilled(self.PromiseResult)
            }
        })

    }
    //reject 函数
    function reject(data) {
        //判断状态
        if (self.PromiseState !== PENDING) { //判断状态,保证promise的状态只能从'pending'变为'rejected'
            return
        }
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = REJECTED // rejected
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data
        //这里需要把回调列表都循环调用一次
        self.callbacks.forEach(callback => {
            //调用失败的回调函数  加判断的原因是防止无回调报错
            if (callback.onRejected) {
                callback.onRejected(self.PromiseResult)
            }
        })

    }

    try {
        //同步调用『执行器函数』
        executor(resolve, reject)
    } catch (error) {
        //修改 promise 对象状态为『失败』
        reject(error)
    }


}

Promise.prototype.then = function (onFulfilled, onRejected) {


    // the Promise Resolution Procedure [[Resolve]](promise2, x)
    function resolvePromise(promise2, x, resolve, reject) {

        // 2.3.1 If promise and x refer to the same object, reject promise with a TypeError as the reason.
        if (promise2 === x) {
            // 防止进入死循环
            reject(new TypeError("Chaining cycle detected for promise"))
        }

        if (x instanceof Promise) {
            // 2.3.2 If x is a promise
            // 判断如果是promise的话,则采用他的最终结果
            x.then(
                value => {
                    resolvePromise(promise2, value, resolve, reject)
                },
                reason => {
                    reject(reason)
                }
            )
        } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
            // 2.3.3 Otherwise, if x is an object or function
            let called = false
            try {
                // 2.3.3.1 Let then be x.then
                // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason
                //  const then = x.then 包裹在try...catch..中
                const then = x.then
                //  If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromis
                if (typeof then === "function") {
                    // 2.3.3.3.1 If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
                    // 2.3.3.3.2 If/when rejectPromise is called with a reason r, reject promise with r.
                    // 2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
                    // 如果then是一个函数,则用x调用它;第一个参数是 resolvePromise,第二个参数是 rejectPromise
                    // 如果同时调用 resolvePromise 和 rejectPromise,或者多次调用同一个参数,则第一个调用具有优先权,后续的调用将被忽略。(所以需要使用 called 进行控制)
                    then.call(x, (y) => {
                        if (called) {
                            return
                        }
                        called = true
                        resolvePromise(promise2, y, resolve, reject)
                    }, (reason) => {
                        if (called) {
                            return
                        }
                        called = true
                        reject(reason)
                    })
                } else {
                    resolve(x)
                }
            } catch (error) {
                // 2.3.3.3.4 If calling then throws an exception e,
                // 2.3.3.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.
                // 2.3.3.3.4.2 Otherwise, reject promise with e as the reason.
                if (called) {
                    return
                }
                called = true
                reject(error)
            }
        } else {
            resolve(x)
        }
    }


    // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
    //2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
    //2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason }
    const promise2 = new Promise((resolve, reject) => { // then 返回的是一个新的promise对象 / 2.2.7. then must return a promise.
        // 当promise的状态为pending的时候就把回调方法保存起来,等待状态改变的时候进行调用
        if (this.PromiseState === PENDING) {
            this.callbacks.push({
                onFulfilled: function (value) {
                    setTimeout(() => {
                        try {
                            // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            resolvePromise(promise2, onFulfilled(value), resolve, reject)
                        } catch (error) {
                            //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                            reject(error)
                        }
                    })
                },
                onRejected: (reason) => {
                    setTimeout(() => {
                        try {
                            // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            resolvePromise(promise2, onRejected(reason), resolve, reject)
                        } catch (error) {
                            //2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                            reject(error)
                        }
                    })
                }
            })
        }
        //如果状态是成功或者失败的话,就直接执行回调方法
        if (this.PromiseState === FULFILLED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onFulfilled(this.PromiseResult), resolve, reject)
                } catch (error) {
                    //  2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })


        }
        if (this.PromiseState === REJECTED) {
            setTimeout(() => { // then方法中的回调是异步执行的
                try {
                    // 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                    resolvePromise(promise2, onRejected(this.PromiseResult), resolve, reject)
                } catch (error) {
                    // 2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
                    reject(error)
                }
            })
        }
    })
    return promise2
}

Promise.defer = Promise.deferred = function () {
    let dfd = {}
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}



module.exports = Promise

最后通过命令来运行这个文件

npx promises-aplus-tests test-promise.js

在这里插入图片描述

可以看到最后所有的测试结果都是通过的

在这里插入图片描述



Promise.prototype.catch

接下来我们来实现Promise的其他原型方法

下面实现的就是

catch

方法,

catch

方法有一个特点就是异常穿透,能够捕获

catch

方法前面

then

方法或者promise中的异常。

其实

catch

方法,本质上也是

then

方法,只是他只接受

onRejected

的回调。

记得我们在前面的实现中,如果promise中发生异常或者then方法中发生异常,最后返回的都是一个

rejected

的promise对象, 接下来调用后面的

then

方法的

onRejected

的回调,但是如果后面的

then

方法没有写

onRejected

的回调,这个时候我们在代码中会判断如果没有的话,我们就给他设置一个

 //2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
 onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason }

这个时候调用的话,就会继续往外抛一个异常,异常就会冒泡到遇到

catch

方法。这个时候我们的

catch

方法其实就是相当于

then

方法中给他指定了

onRejected

的回调。

所以

Promise.prototype.catch

的回调如下:

Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected)
}

测试结果:

在这里插入图片描述



Promise.prototype.finally

之前我们讲过finally本质上是then方法的特例。

特点就是:如果finally中的回调抛出错误,那么最后返回一个

rejected

的新promise。其他情况则和旧promise的状态和值一样。

promise
.finally(() => {
  // 语句
});

// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

所以最终我们实现出来的

Promise.prototype.finally

方法如下:

Promise.prototype.finally = function (callback) {
    return this.then(
        (data) => {
            callback()
            return data
        },
        (error) => {
            callback()
            throw error
        }
    )
}

来看测试结果

在这里插入图片描述



Promise.resolve

接下来我们来开始讲Promise的静态方法了

之前也讲过

Promise.resolve

其实就是简写的

new Promise

的方式

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

Promise.resolve()方法的参数分成四种情况

  1. 如果参数是 Promise 实例,那么

    Promise.resolve

    将不做任何修改、原封不动地返回这个实例。
  2. 参数是一个

    thenable

    对象,

    Promise.resolve()

    方法会将这个对象转为 Promise 对象,然后就立即执行

    thenable

    对象的

    then()

    方法。
  3. 参数不是具有then()方法的对象,或根本就不是对象

    如果参数是一个原始值,或者是一个不具有

    then()

    方法的对象,则

    Promise.resolve()

    方法返回一个新的 Promise 对象,状态为

    resolved
  4. 不带有任何参数,·Promise.resolve()`方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

这四点中后面三点都是跟

new Promise

的行为是一致的,只有第一点是不一致的。

我们可以看看ES6中promise的结果

在这里插入图片描述

在这里插入图片描述

所以在实现上我们只需要对第一种做特殊处理

Promise.resolve = function (value) {
    return value instanceof Promise
        ? value
        : new Promise((resolve) => resolve(value))
}

测试结果

在这里插入图片描述



Promise.reject


Promise.reject(reason)

方法也会返回一个新的 Promise 实例,该实例的状态为

rejected

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

我们来看具体实现

Promise.reject = function (reason) {
    return new Promise((resolve, reject) => reject(reason))
}

测试结果:

在这里插入图片描述



Promise.race


Promise.race()

方法是将多个 Promise 实例,包装成一个新的 Promise 实例。

Promise.race()

方法的参数,如果不是 Promise 实例,就会将参数转为 Promise 实例,再进一步处理。运行的结果是参数里谁最先改变prmoise的状态,返回的新的promise的状态和值就与最先改变prmoise的状态的promise一致。

在这里

Promise.race()

方法的参数,如果不是 Promise 实例,就会将参数转为 Promise 实例,再进一步处理。这里我们可以用

Promise.resolve

来进行处理

所以具体的实现如下

Promise.race = function (promises) {
    //需要注意的是,如果Promise.race接收到的是一个空数组([]),则会一直pending
    return new Promise((resolve, reject) => {
        promises.forEach((promise) => {
            Promise.resolve(promise).then(v => resolve(v), r => reject(r))
        })
    })
}

测试结果:

在这里插入图片描述



Promise.all


Promise.all()

方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

Promise.all()

方法接受一个数组作为参数,参数中的实例如果不是promise对象,就会先

Promise.resolve

方法,将参数转为

Promise

实例,再进一步处理。

新返回的promise对象分为两种情况

  1. 如果参数中的实例的状态都是

    fulfilled

    ,最终才会变成

    fulfilled

    的状态,此时参数中所有实例的返回值构成数组,传递给promises的回调函数。
  2. 如果参数中的实例有一个是

    rejected

    ,那最终就是

    rejected

    的状态,并且此时第一个被reject的实例的返回值,会传递给promises的回调函数。

下面来看具体的实现:

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        // 如果Promise.all接收到的是一个空数组([]),会立即resolve。
        if (!promises.length) {
            resolve([])
        }
        let result = []
        let resolvedPro = 0
        for (let index = 0, length = promises.length; index < length; index++) {
            Promise.resolve(promises[index]).then(
                (data) => {
                    // 注意,这里要用index赋值,而不是push。因为要保持返回值和接收到的promise的位置一致性。
                    result[index] = data  //let的块级作用域
                    if (++resolvedPro === length) {
                        resolve(result)
                    }
                },
                (error) => {
                    reject(error)
                }
            )
        }
    })
}

测试结果:

在这里插入图片描述



参考


JavaScript Promises:简介


剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类


史上最易读懂的 Promise/A+ 完全实现


手写 Promise


Promise A+ 规范


这次彻底搞懂 Promise(手写源码多注释篇)


https://github.com/then/promise


Promise的实现与标准


按照 Promise/A+ 手写Promise,通过promises-aplus-tests的全部872个测试用例


promise/A+规范翻译以及手写实现


【尚硅谷Web前端Promise教程从入门到精通-哔哩哔哩】


基于PromisesA+规范手写Promise


https://github.com/shifengming/promise/blob/master/promise.js



版权声明:本文为cckevincyh原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。