DEV Community

inno
inno

Posted on • Edited on

参照Promise/A+规范自定义实现Promise

Promise/A+规范

https://promisesaplus.com/

Promise相关问题

https://juejin.cn/post/7042679110111330312#heading-9

Terminology

  • “promise” is an object or function with a then method whose behavior conforms to this specification.
  • “thenable” is an object or function that defines a then method.
  • value 是promise状态成功时的值,包括 undefined/thenable或者是 promise
  • exception 是一个使用throw抛出的异常值
  • reason 是promise状态失败时的值

Requirements

Promise 必须处于以下三个状态之一: pending, fulfilled 或者是 rejected

1.如果promise在pending状态
---可以变成 fulfilled 或者是 rejected

2.如果promise在fulfilled状态
---不会变成其它状态
---必须有一个value值

3.如果promise在rejected状态
---不会变成其它状态
---必须有一个promise被reject的reason

The then Method

  • promise必须提供一个then方法,来访问最终的结果

  • promise的then方法接收两个参数
    promise.then(onFulfilled, onRejected)

1.onFulfilled 和 onRejected 都是可选参数

 onFulfilled 必须是函数类型

 onRejected 必须是函数类型
Enter fullscreen mode Exit fullscreen mode

2.如果 onFulfilled 是函数

1.必须在promise变成 fulfilled 时,调用 onFulfilled,参数是promise的value
2.在promise的状态不是 fulfilled 之前,不能调用
3.onFulfilled 只能被调用一次
Enter fullscreen mode Exit fullscreen mode

3.如果 onRejected 是函数:

1.必须在promise变成 rejected 时,调用 onRejected,参数是promise的reason
2.在promise的状态不是 rejected 之前,不能调用
3.onRejected 只能被调用一次
Enter fullscreen mode Exit fullscreen mode

4.onFulfilled 和 onRejected 必须作为函数被调用
5.then方法可能被多次调用

1.如果promise变成了 fulfilled态,所有的onFulfilled回调都需要
  按照then的顺序执行
2.如果promise变成了 rejected态,所有的onRejected回调都需要
  按照then的顺序执行
Enter fullscreen mode Exit fullscreen mode

7.then必须返回一个promise

promise2 = promise1.then(onFulfilled, onRejected);
1.onFulfilled 或 onRejected 执行的结果为x,调用 resolvePromise
2.如果 onFulfilled 或者 onRejected 执行时抛出异常e,promise2需要被reject
3.如果 onFulfilled 不是一个函数,promise2 以promise1的值fulfilled
4.如果 onRejected 不是一个函数,promise2 以promise1的reason rejected
Enter fullscreen mode Exit fullscreen mode

自定义Promise

//难点分析
// 1.promise中有异步函数,then方法执行时,promiseStatus仍然是pedding状态,如何在promiseStatus改变时调用then的方法
// 2.then返回一个promise对象,当promise中有异步调用时,如何调用
// 3.catch异常穿透问题
enum Status {
    Pedding = "Pedding",
    Fulfilled = "Fulfilled",
    Rejected = "Rejected"
}
interface callBackType{
    onResolve:(param:any)=>any
    onReject?:(param:any)=>any
}
class CustomPromise {
   private  promiseStatus: Status = Status.Pedding
   private  promiseResult: unknown
   private  callBacks:callBackType[]=[]
    constructor(executor) {
        const resolve = (data: any) => {
            if (this.promiseStatus !== Status.Pedding) {
                return
            }
            this.promiseStatus = Status.Fulfilled
            this.promiseResult = data
            if (this.callBacks.length!=0) {
             setTimeout(()=>{
                this.callBacks.forEach(item=>item.onResolve(this.promiseResult)) 
             },0)   
            }
        }
        const reject = (error: any) => {
            this.promiseStatus = Status.Rejected
            this.promiseResult = error
            if (this.callBacks.length!=0) {
                setTimeout(()=>{
                    this.callBacks.forEach(item=>{
                        if (item.onReject) {
                            item.onReject(this.promiseResult) 
                        }

                    }) 
                 },0)  

            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onResolve, onReject?:(params:any)=>any) {
        return new CustomPromise((resolve,reject)=>{
 // 发现onReject回调函数没有传递就自定义一个。
//并且将前一个then方法执行返回的失败的Promise一直向下抛,
//直到遇见可以处理失败状态的catch函数
            if (typeof onReject!='function') {
                onReject=function (params) {
                    throw params
                }   
            }
// onResolve也是一样将结果一直向下传递,直到遇到处理的回调函数
            if (typeof onResolve !== 'function') {
                onResolve = value => value
            }
            if (this.promiseStatus === Status.Fulfilled) {
                try {
                    const value= onResolve(this.promiseResult)  
                    resolve(value)
                } catch (error) {
                    reject(error)
                }              
            }
            if (this.promiseStatus === Status.Rejected) {
                try {
                    const value= onReject(this.promiseResult)
                    resolve(value)
                } catch (error) {
                    reject(error)
                }    
            }
            if (this.promiseStatus === Status.Pedding) {
              this.callBacks.push({onResolve(param){
                try {
                  const value=onResolve(param)
                  resolve(value)
                } catch (error) {
                  reject(error)  
                }
              },onReject(param){
                try {
                    if (onReject) {
                        const value=onReject(param)
                        resolve(value)  
                    }

                  } catch (error) {
                    reject(error)  
                  }
              }})
            }
        })
    }
    catch(onReject:(param:any)=>void){
        this.then(undefined,onReject)
    }
    static all(promises){
        return new CustomPromise((resolve, reject) => {
            let count = 0
            let res:any[]= []
            for(let i = 0 ; i < promises.length; i ++){
                promises[i].then(value => {
                    count ++ 
                    res[i] = value 
                    if (count === promises.length) {
                        resolve(res)
                    }
                },reason => {
                    reject(reason)
                })
            }
            });
    }
    static race(promises){
        return new CustomPromise((resolve, reject) => {
            promises.forEach(promise => {
                promise.then(value => {
                    resolve(value)
                },reason => {
                    reject(reason)
                })
            })
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)