符合promiseA+的抄袭

557 阅读5分钟

最近学习了 promise 的实现,所以写篇博客记录下自己的收获,也可以加深自己的理解和记忆

什么是promise?

Promise 是 es6 新增的对象,其主要功能是处理异步操作,通过实例化对象来管理异步状态,及then方法处理异步结果

来看看其用法

new Promise((resolve, reject) ==> {
    // 伪代码
    ajax((res) => {
        if (res.code === 200) {
            // 成功状态,调用resolve
            resolve(res.data)
        } else {
            // 失败状态,调用reject
            reject(res)
        }
    })
}).then((data) => {
    // 处理成功状态
}, () => {
    // 处理失败状态
})

可以看到在 promise 中,我们通过调用 resolve reject 来更改异步状态及传递异步结果,然后在 then 函数中处理异步结果。不同于使用回调函数来处理异步结果的方法,promise 通过使用 then 来处理异步结果,同时可以使用链式调用来一步步处理结果,例如

new Promise().then().then().then()

其中在 then 函数也可以创建新的 promise 来进行异步操作

new Promise().then(() => { return new Promise() }).then().then()

promise的实现

promiseA+规范

看网上的实现文章很多都谈到了 promiseA+,这是个什么东东呢?

看看官网怎么写的

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

一个开放,健全且通用的 Javascript Promise 标准。由开发者制定,供开发者参考

可以看出,promiseA+就是份指导 promise 实现的规范,它定义了 promise 的状态,如何改变状态,then 方法的使用及返回值。

可以说,只有写出了符合 promiseA+ 的 promise 才是真正实现了 promise

实现代码

直接贴出全部代码吧,毕竟是抄其它大佬的

// promise的唯三状态
// 等待异步结果
const PENDING = 'pending' 
// 执行状态
const FULFILLED = 'fulfilled'
// 拒绝状态
const REJECTED = 'rejected'

function MyPromise(exector) {
    this.status = PENDING

    // 等待异步结果的待执行函数(实现then的链式调用)
    // promise执行队列
    this.fulfilledList = []
    // promise拒绝队列
    this.rejectedList = []

    // 参数 resolve
    const resolve = value => {
        if (this.status === PENDING) {
            // 改变状态为执行状态
            this.status = FULFILLED
            this.value = value
            
            // 异步执行执行队列
            setTimeout(() => {
                this.fulfilledList.forEach((fn) => {
                    fn()
                })
            })
        }
    }

    const reject = reason => {
        if (this.status === PENDING) {
            // 改变状态为拒绝状态
            this.status = REJECTED
            this.reason = reason

            // 异步执行拒绝状态
            setTimeout(() => {
                this.rejectedList.forEach((fn) => {
                    fn()
                })
            })
        }
    }

    try {
        // 执行传入参数exector
        exector(resolve, reject)
    } catch(e) {
        reject(e)
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    // 成功和失败的处理函数,如果没有对应的处理函数则将值和状态传递下去
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    let promise2 = null

    // 规范规定了then的返回值是新promise2,这是实现 then 的链式调用的基础
    // 返回值 promise2 的状态并不依赖于 promise 的状态
    // 其状态由处理函数 onFulfilled onRejected 及其执行的返回结果决定(可能是 执行状态 拒绝状态 等待状态)
    // 所以 new Promise().then().then() 中有可能出现第一个then执行拒绝函数和第二个then执行执行函数
    // 可以说,第二个then完全依赖于上一个then,和最初的promise没有关系
    promise2 = new MyPromise((resolve, reject) => {
        // promise已经是执行状态
        if (this.status === FULFILLED) {
            setTimeout(() => {
                // 异常则更改promise为拒绝状态
                try {
                    // 执行函数获得结果x
                    const x = onFulfilled(this.value)
                    
                    // 执行promise解决程序
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }

        // 异常则更改promise为拒绝状态
        if (this.status === REJECTED) {
            setTimeout(() => {
                // 异常则拒绝
                try {
                    // 可以看出,只要onFulfilled 和 onRejected 正常执行了就会走promise处理程序,否则就会reject
                    const x = onRejected(this.reason)
                    
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }

        // promise还处于等待状态
        if (this.status === PENDING) {
            // 同时往执行和拒绝队列中添加处理函数,此时不知道后面的状态及会最终会执行的队列
            this.fulfilledList.push(() => {
                try {
                    const x = onFulfilled(this.value)
                    
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })

            this.rejectedList.push(() => {
                try {
                    const x = onRejected(this.reason)
                    
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }
    })

    // 返回新的promise
    return promise2
}

// promise的解决程序
// 大概为以下解决思路,主要就是判断x是不是promise或者是否有then方法,如果是则获取x状态(执行x.then递归promise解决程序),否则直接resolve(x)
// 1. 判断x是否和promise为同一个对象,是则reject(类型错误)
// 2. 判断x是否为Promise实例,是则将x的状态作为promise的状态,实际就是执行x.then获取x的状态及结果来递归执行promise解决程序
// 3. 判断x是否为函数或对象,如果是x.then是函数则执行then获取x的状态及结果来递归执行promise解决程序
// 4. 如何x不是对象或者x.then不是函数,则resolve(x)
function resolvePromise (promise, x, resolve, reject) {
    // x 和 promise 相等则 reject 类型错误
    if (x === promise) {
        return reject(new TypeError('cycle chain'))
    }

    // x 是个promise
    if (x instanceof MyPromise) {
        // 将x的状态作为promise的状态,如何获取x的状态,通过then方法
        x.then(y => {
            // 继续执行promise解决程序
            resolvePromise(promise, y, resolve, reject)
        }, reject)
    } else if (x && (typeof x === 'object' || typeof x === 'function')) {
        let then = null
        // 防止重复调用
        let used = false
        
        // 规范定义的,取then错误则reject
        try {
            then = x.then
        } catch (e) {
            reject(e)
        }

        // 如果x.then是个函数
        if (typeof then === 'function') {
            try {
                // 执行then,使用then的状态作为promise状态
                then.call(x, y => {
                    if (used) return
                    used = true
                    resolvePromise(promise, y, resolve, reject)
                }, r => {
                    if (used) return
                    used = true
                    reject(r)
                })
            } catch(e) {
                if (used) return
                reject(e)
            }
        } else {
            // 普通对象,resolve
            if (used) return;
            resolve(x)
        }
    } else {
        // x 不是对像或函数 resolve
        resolve(x)
    }
}

以上便是一个符合 promiseA+ 规范的 promise 实现,口说无凭,如何证明它符合规范呢?

测试

可以使用官方测试工具 promises-aplus-tests

安装

npm install promises-aplus-tests -g

为你实现的 promise 添加 deferred 方法

MyPromise.deferred = function() {
  var result = {};
  result.promise = new MyPromise(function(resolve, reject){
    result.resolve = resolve;
    result.reject = reject;
  });

  return result;
}

模块化导出 promise

module.exports = MyPromise

运行测试脚本

promises-aplus-tests <File>

参考


欢迎到前端学习打卡群一起学习~516913974