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

手把手带你实现符合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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值