Promise A+规范

promise基础:promise是一个构造函数,参数为一个,是一个要执行的函数,称为executor

  1. let promise = new Promise((resolved,rejected)=>{})//executor

一、基础定义

1.promise是一个带有then方法的objectfunction

2.then是一个function

3.value是一个合法的JavaScript变量

4.exception 是一个抛出的错误

5.reason 是一个说明promise变成rejected的原因

二、要求

promise 状态

promise有三个状态:pendingfulfilledrejected

1.promise初始状态为pending

2.promise状态为fulfilled时,状态不能再更改,且一定要有一个value,也是不能再更改的

3.promise状态为rejected时,状态不能再更改,且一定要有一个reason,也是不能再更改的

关于then方法

promise必须提供一个then方法,去接收后续操作

  1. promise.then(onFulfilled,onRejected)

1.onFulfilledonRejected都是可选的,若不是函数,则会被忽略

2.onFulfilled是一个函数且当promise状态变为fulfilled的时候就会执行,且传入一个参数为value,每个then里面的onFulfilled只能被调用一次

3.onRejected是一个函数且当promise状态变为rejected一个参数为reason,每个then里面的onRejected只能被调用一次

4.onFulfilledonRejected必须作为函数被调用,且里面不能有this

5.一个promisethen是可以有多个的,但是其中的onFulfilledonRejected都必须按照顺序来调用

  1. let promise = new Promise(()=>{})
  2. // 按照1 2 3的顺序来
  3. promise.then(()=>{
  4. console.log(1)
  5. })
  6. promise.then(()=>{
  7. console.log(2)
  8. })
  9. promise.then(()=>{
  10. console.log(1)
  11. })
  12. promise.then(()=>{
  13. console.log(3)
  14. })

简单实现一个Promise

由上面要求可得知,promise一共有三个状态,分别是PENDINGFULFILLEDREJECTED

promise状态只有为PENDING时,才能改变状态,同时赋值

当执行then方法时,入参为两个函数,分别为onFulfilledonRejected

故有如下代码

  1. const PENDING = "PENDING",
  2. FULFILLED = "FULFILLED",
  3. REJECTED = "REJECTED"
  4. class MyPromise {
  5. constructor(executor) {
  6. this.state = PENDING,
  7. this.value = undefined,
  8. this.reason = undefined;
  9. const resolve = (value) => {
  10. if (this.state === "PENDING") {
  11. this.state = FULFILLED;
  12. this.value = value
  13. }
  14. }
  15. const rejecte = (reason) => {
  16. if (this.state === "PENDING") {
  17. this.state = REJECTED
  18. this.reason = reason
  19. }
  20. }
  21. try {
  22. executor(resolve, rejecte)
  23. } catch (e) {
  24. rejecte(e)
  25. }
  26. }
  27. then(onFulfilled, onRejected) {
  28. if (this.state === "FULFILLED") {
  29. onFulfilled(this.value)
  30. }
  31. if (this.state === "REJECTED") {
  32. onRejected(this.reason)
  33. }
  34. }
  35. }
  36. module.exports = MyPromise

这样就可以简单实现promise的基础功能的

但此时还不能实现异步及多个then的依次调用,所以我们下面要用到发布-订阅的模式

const PENDING = "PENDING",
    FULFILLED = "FULFILLED",
    REJECTED = "REJECTED"
class MyPromise {
    constructor(executor) {
        this.state = PENDING,
            this.value = undefined,
            this.reason = undefined;

        // 添加两个容器保存对应的事件
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []

        const resolve = (value) => {
            if (this.state === "PENDING") {
                this.state = FULFILLED;
                this.value = value
                // 执行等待事件
                this.onFulfilledCallbacks.forEach(item => {
                    item()
                })
            }

        }

        const rejecte = (reason) => {
            if (this.state === "PENDING") {
                this.state = REJECTED
                this.reason = reason
                // 执行等待事件
                this.onRejectedCallbacks.forEach(item => {
                    item()
                })

            }
        }
        try {
            executor(resolve, rejecte)
        } catch (e) {
            rejecte(e)
        }
    }

    then(onFulfilled, onRejected) {
        if (this.state === "FULFILLED") {
            onFulfilled(this.value)
        }
        if (this.state === "REJECTED") {
            onRejected(this.reason)
        }
        // 异步时 将事件添加到等待队列里面等待执行
        if (this.state === "PENDING") {
            if (typeof onFulfilled === "function") {
                this.onFulfilledCallbacks.push(() => {
                    onFulfilled(this.value)
                })
            }

            if (typeof onRejected === "function") {
                this.onRejectedCallbacks.push(() => {
                    onRejected(this.reason)
                })
            }
        }
    }
}

module.exports = MyPromise

扩展要求-链式调用

promiseA+规范里面要求then要返回一个新的promise,且要求不管是onFulfilled还是onRejected都要返回一个x并且当抛出异常的时候都需要拿到这个异常返回e,并且对于onFulfilledonRejected要做异步,所以下面要将then方法改造

// 如果FulFilled和Rejected的时候没有setTimeout的话会报错,因为此时promise2还没构造出来
//resolvePromise是针对 onFulfilled 和 onrejectd里的返回值做判断,是否为一个promise

// 判断x是否一个promise
// 都是根据promiseA+规范中的2.3.x 的要求去设定的
function resolvePromise(promise2, x, resolve, reject) {
    // 规范2.3.1 当promise2 与 x为同一个引用时,需要抛出 TypeError
    // let p2 = p.then((res) => {
    //     return p2
    // })
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<MyPromise>'))
    }

    // 这样就可能是个Promise
    if ((typeof x === "object" && x != null) || typeof x === "function") {
        try {
            let then = x.then; 
            let called = false
            // 如果then是function,就认为他是个Promise
            if (typeof then === "function") {
                // 规范定义,如果被调用过,就不能重复调用
                then.call(x, (y) => {
                    if (called) return
                    called = true
                    resolve(y)
                }, (r) => {
                    if (called) return
                    called = true
                    reject(r)
                })
            } else {
                // 不是Promise就返回x
                resolve(x)
            }
        } catch (e) {
            reject(e)
        }
    } else {
        resolve(x)
    }
}

 then(onFulfilled, onRejectd) {
        //每一个都加上try catch
        let promise2 = new MyPromise((resolve, reject) => {
            // 返回一个x 
            let x;
            if (this.state === "FULFILLED") {
                setTimeout(() => {
                    try {
                        x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })

            }
            if (this.state === "REJECTED") {
                setTimeout(() => {
                    try {
                        x = onRejectd(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })

            }
            // 异步时 将事件添加到等待队列里面等待执行
            if (this.state === "PENDING") {
                if (typeof onFulfilled === "function") {
                    this.onFulfilledCallbacks.push(() => {
                        try {
                            x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                }

                if (typeof onRejectd === "function") {
                    this.onRejectdCallbacks.push(() => {
                        try {
                            x = onRejectd(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                }
            }
            // return promise2
        })
        return promise2
    }

然后我们运行一下结果,以下基本上都和Promise一致了,除了一些情况

const MyPromise = require("./myPromise3")

let promise1 = new MyPromise((resolve, reject) => {
    // console.log(3);
    //setTimeout(() => {
    resolve("promise1");
    //}, 1000)
    // console.log(a);
    // console.log(4);
    //reject(100)
})
let promise2 = promise1.then(() => {
    // return 1
    // return new Error("error") // error
    // return Promise.resolve("Promise resolve") // Promise resolve
    return new MyPromise((resolve, reject) => {
        // resolve("new MyPromise") // new MyPromise

        // setTimeout(() => {
        //     resolve("setTimeout new MyPromise") //setTimeout new MyPromise
        // })
        // 异步 + 多层嵌套 
        setTimeout(() => {
            resolve(new MyPromise((resolve, reject) => {
                resolve("setTimeout resolve new MyPromise") // 此时这里打印出一个MyPromise的实例
            })) //setTimeout new MyPromise
        })
    })
}, (reason) => {
    console.log(reason);
    return reason
})
promise2.then((res) => {
    console.log("res", res);
}, (reason) => {
    console.log(reason);
    return reason
})

继续优化,这里主要是一个递归的问题

function resolvePromise(promise2, x, resolve, reject) {
...
// 将这里的resolve改为递归调用resolvePromise,如果是Promise就继续执行,这样就不怕嵌套问题了
if (typeof then === "function") {
                // 规范定义,如果被调用过,就不能重复调用
                then.call(x, (y) => {
                    if (called) return
                    called = true
                    resolvePromise(promise2, y, resolve, reject)
                }, (r) => {
                    if (called) return
                    called = true
                    reject(r)
                })
            } else {
                // 不是Promise就返回x
                resolve(x)
            }
    ...
}

当链式调用时,这时没有东西打印出来,因为在规范中规定,onFulfilledonRejected是可选的,且当他们为非函数时则要忽略,所以当它们不存在时,则默认将参数传递下去。

promise2.then().then().then().then((res) => {
    console.log("res", res);
}, (reason) => {
    console.log(reason);
    return reason
})

所以要修改一下then方法

then(onFulfilled, onRejectd) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => {
            return value
        }
        onRejectd = typeof onRejectd === "function" ? onRejectd : (reason) => {
            throw (reason)
        }
        ...
 }

此时还缺一个.catchcatch方法,catch其实就是一个then方法

 catch (errorCallBack) {
        this.then(null, errorCallBack)
 }

然后就可以在.then后面加.catch

promise2.then().then().then().then((res) => {
    console.log("res", res);
}, (reason) => {
    console.log(reason);
    return reason
}).catch((e) => {
    console.log("catch:", e);
})