promiseA+规范实现promise

131 阅读5分钟

参考链接

规范的步骤很详细,但是可能不懂规范书写方式的话,看起来可能有些困难。

前置知识

promise 有三种状态 pending fulfilled rejected

一旦状态改变就不可逆

pending ---> fulfilled resolve

pending --- rejected rejected

OK 了解前置知识后可以开始了

首先 对应两种状态,成功的时候我们称它的值为value 失败的时候也会有对应的reason

class myPromise {
    constructor(executor) {
        this.state = 'pending'
        this.value = undefined
        this.reason = undefined
        let resolve = (value) => {
            this.state = 'fulfilled' // 状态变更resolve 
            this.value = value
        }
        let reject = (reason) => {
            this.state = 'rejected'
            this.reason = reason
        }
        executor(resolve, reject)
    }
}

然后我们实现then , then接收两个参数onFulfilled 、onRejected,

  • 当状态为成功 则执行onFulfilled
  • 否则执行onRejected
class myPromise {
    constructor(executor) {
        this.state = 'pending'
        this.value = undefined
        this.reason = undefined
        let resolve = (value) => {
            this.state = 'fulfilled' // 状态变更resolve 
            this.value = value
        }
        let reject = (reason) => {
            this.state = 'rejected'
            this.reason = reason
        }
        executor(resolve, reject)
    }
       // +++++++++++++++++++++
    then(onFulfilled, onRejected) {
        if (this.state === 'fulfilled') {
            onFulfilled(this.value)
        } else if (this.state === 'rejected') {
            onRejected(this.reason)
        }
    }
}

至此,面对同步的逻辑,是可以完美运行的,但是碰到异步代码还有点招架不住,因为异步代码的状态不是立即确定的,所以我们需要等待它执行完后再确定。

所以,我们需要添加两个数组,分别存储成功和失败的回调,等到状态改变后执行,同时在then的penging状态 下向回调中添加任务

class myPromise {
    constructor(executor) {
        this.state = 'pending'
        this.value = undefined
        this.reason = undefined
        this.onResolveCallbacks = [] // +++
        this.onRejectCallbacks = [] // +++
        let resolve = (value) => {
            this.state = 'fulfilled' // 状态变更resolve 
            this.value = value
            this.onResolveCallbacks.forEach(fn => fn())// +++
        }
        let reject = (reason) => {
            this.state = 'rejected'
            this.reason = reason
            this.onRejectCallbacks.forEach(fn => fn())// +++

        }
        executor(resolve, reject)
    }

    then(onFulfilled, onRejected) {
        if (this.state === 'fulfilled') {
            onFulfilled(this.value)
        } else if (this.state === 'rejected') {
            onRejected(this.reason)
        } else {       // ++++++++++++++++++++

            this.onResolveCallbacks.push(() => {
                onFulfilled(this.value)
            })

            this.onRejectCallbacks.push(() => {
                onRejected(this.reason)
            })


        }
    }
}

这时候我们碰到setTimeout这种异步任务也可以执行了,但是如果有返回值或返回的结果是一个promise,我们这时候还无法进行链式调用,我们来看一下规范:

为了达成链式,我们默认在第一个then里返回一个promise。秘籍规定了一种方法,就是在then里面返回一个新的promise,称为promise2promise2 = new Promise((resolve, reject)=>{})

将这个promise2返回的值传递到下一个then中 如果返回一个普通的值,则将普通的值传递给下一个then中

当我们在第一个then中return了一个参数(参数未知,需判断)。这个return出来的新的promise就是onFulfilled()或onRejected()的值

秘籍则规定onFulfilled()或onRejected()的值,即第一个then返回的值,叫做x,判断x的函数叫做resolvePromise

  • 首先,要看x是不是promise。
  • 如果是promise,则取它的结果,作为新的promise2成功的结果
  • 如果是普通值,直接作为promise2成功的结果 所以要比较x和promise2
  • resolvePromise的参数有promise2(默认返回的promise)、x(我们自己return的对象)、resolve、reject resolve和reject是promise2的
then(onFulfilled, onRejected) {
        // 为了实现链式调用,我们必须返回一个promise
        let promise2 = new myPromise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                let x = onFulfilled(this.value) //获取返回值

                resolvePromise(promise2, x, resolve, reject) //判断返回值的类型
            } else if (this.state === 'rejected') {

                let x = onRejected(this.reason) //获取返回值
                resolvePromise(promise2, x, resolve, reject) //判断返回值的类型

            } else {

                this.onResolveCallbacks.push(() => {
                    let x = onFulfilled(this.value) //获取返回值

                    resolvePromise(promise2, x, resolve, reject) //判断返回值的类型
                })

                this.onRejectCallbacks.push(() => {
                    let x = onRejected(this.reason) //获取返回值
                    resolvePromise(promise2, x, resolve, reject) //判断返回值的类型
                })


            }
        })

        return promise2
    }

实现resolvePromise

秘籍规定了一段代码,让不同的promise代码互相套用,叫做resolvePromise

如果 x === promise2,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误

let p = new Promise(resolve => {
  resolve(0);
});
var p2 = p.then(data => {
  // 循环引用,自己等待自己完成,一辈子完不成
  return p2;
})

1、判断x

Otherwise, if x is an object or function,Let then be x.then

  • x 不能是null
  • x 是普通值 直接resolve(x)
  • x 是对象或者函数(包括promise),let then = x.then

2、当x是对象或者函数(默认promise)

  • 声明了then
  • 如果取then报错,则走reject()
  • 如果then是个函数,则用call执行then,第一个参数是this,后面是成功的回调和失败的回调
  • 如果成功的回调还是pormise,就递归继续解析

3、成功和失败只能调用一个 所以设定一个called来防止多次调用

function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {
        return reject(new TypeError("Chain cycle detected"))
    }

    let called
    if (typeof x !== null && (typeof x === 'object' || typeof x === 'function')) { //如果返回值是promise

        try {
            let then = x.then
            if (typeof then === 'function') {
                then.call(x, v => {
                    if (called) return;
                    called = true
                    resolve(v)

                    resolvePromise(promise2, v, resolve, reject)
                }, r => {
                    if (called) return;
                    called = true
                    reject(r)
                })
            } else {
                resolve(x)
            }
        } catch (error) {
            if (called) return;
            called = true
            reject(error)
        }

    } else { //如果是普通值
        resolve(x)
    }
}

then(onFulfilled,onRejected) { // onFulfilled如果不是函数,就忽略onFulfilled,直接返回value onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; // onRejected如果不是函数,就忽略onRejected,直接扔出错误 onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }; let promise2 = new Promise((resolve, reject) => { if (this.state === 'fulfilled') { // 异步 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }; if (this.state === 'rejected') { // 异步 setTimeout(() => { // 如果报错 try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }; if (this.state === 'pending') { this.onResolvedCallbacks.push(() => { // 异步 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); this.onRejectedCallbacks.push(() => { // 异步 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0) }); }; }); // 返回promise,完成链式 return promise2; } }