参照Promise/A+规范自定义实现Promise
Published: 2023-05-18 09:48:50

# 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 必须是函数类型
```

2.如果 onFulfilled 是函数

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

3.如果 onRejected 是函数:

```
1.必须在promise变成 rejected 时，调用 onRejected，参数是promise的reason
2.在promise的状态不是 rejected 之前，不能调用
3.onRejected 只能被调用一次
```
4.onFulfilled 和 onRejected 必须作为函数被调用
5.then方法可能被多次调用
```
1.如果promise变成了 fulfilled态，所有的onFulfilled回调都需要
  按照then的顺序执行
2.如果promise变成了 rejected态，所有的onRejected回调都需要
  按照then的顺序执行
```
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
```
# 自定义Promise
```typescript
//难点分析
// 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)
                })
            })
        });
    }
}

```