手写Promise

157 阅读7分钟

Promise/A+ 规范

要实现一个Promise,首先应该遵守一下 Promise/A+ 规范,Promise/A+涉及较广,这里只介绍核心的部分。

中文翻译规范:juejin.cn/post/684490…

英文翻译规范:promisesaplus.com/

Promise的状态

  • promise只有三种状态,请求态(pending)、完成态(fulfilled)、拒绝态(rejected)。
  • promise的状态变化是不可逆,只能从pinding=>fulfilled或者pending=>reject

Promise 的then方法

  • promise的then方法接受两个参数,一个是onFulfilled,另一个是onRejected。两者必须是函数,如果不是函数会被忽略。
  • 如果onFulfilled是函数,当状态变成fulfilled时会触发,并接Resolve传过来的值
  • 如果onRejected是函数,当状态变成reject时会触发,并接受Reject传过来的值
  • then方法返回的是一个promise
  • them方法能多次调用,按照调用顺序执行代码,接受的值是上一次then返回的值

Promise的解析过程

Promise的resolve方法调用时,会根据不同的值进行不同的操作。

  • 如果传入的是Promise本生,则抛出一个循环Promise的错误
  • 如果传入的是一个新的Promise,则会等待新的Promise状态改变后返回新的值,如果新的Promise的状态不是fulfilled,调用新的promise的then方法,直到状态改变为止
  • 如果resolve的是一个thenable对象,当成一个新的promise处理。
  • 如果是其他值,则按照正常的resolve处理

Promise的流程图

  • 当Promise实例化时接受一个回调函数,回调函数接受两个参数一个是resolve,另一个是reject.
  • 当实例化后会执行回调函数,当执行成功或者是我们想要的结果时会触发resolve,然后能在then方法中第一个参数捕捉到
  • 当执行错误或者不是我们想要的结果时,触发reject,可以在catch中或then的第二个参数中捕捉到

手写promise

需要实现的内容

1、state 存放当前的状态。

2、value 存放成功状态的值。

3、reason 存放失败状态的值。

4、then 方法,返回值也是一个 Promise。

5、catch 方法。

6、finally 方法,成功和失败都会调用一次。

7、静态方法,如 Promise.all、Promise.resolve。

实现步骤

1、实现一个 promise ,在 setTimeout 中去 resolve。 ok

 const PENDING = 'pending'
      const FULFILLD = 'fulfilled'
      const REJECT = 'reject'
      class MyPromise {
        constructor(fn) {
          this.state = PENDING //初始状态我饿pending
          this.value = 'undefined' //初始值为value
          this.resolveCallback = [] //用来存储then的回调函数
          const resolve = (val) => {
            this.val = val
            this.state = FULFILLD //状态变为fulfilled;
            //执行所以的then方法,then可能有多个
            this.resolveCallback.map((callBack) => {
              callBack(val)
            })
          }
          const reject = (err) => {
            this.state = REJECT //状态变为reject
          }
          fn(resolve, reject)
        }
        then(onFulfilled, onRejected) {
          if (this.state === PENDING) {
            this.resolveCallback.push(onFulfilled) //只能在请求态执行
          }
        }
      }


 //实验
      new MyPromise((resolve) => {
        setTimeout(() => {
          resolve('step1')
        })
      }).then((res) => {
        console.log(res)//step1
      })

2、实现一个 promise,支持同步 resolve。 ok

  • 由于初始化的时候then还没有挂载上去,所以此时resolveCallback是个空的数组,所以要等then挂载上去才能执行resolve
//resolve的修改
const resolve=val=>{
    setTimeOut(()=>{
         this.val = val;
         this.state = FULFILLD //状态变为fulfilled;
            //执行所以的then方法,then可能有多个
         this.resolveCallback.map((callBack) => {
              callBack(val)
        })
    })
}

3、实现一个 promise,防止 resolve 多次。 ok

  • 在promise中如果resolve多次,只会resolve第一次的值,实现该步骤只需要在resolve的时候判断下状态是否pending
const resolve=val=>{
    setTimeOut(()=>{
    if(this.state===PENDING){
            this.val = val;
         this.state = FULFILLD //状态变为fulfilled;
            //执行所以的then方法,then可能有多个
         this.resolveCallback.map((callBack) => {
              callBack(val)
        })  
    }
    })
}

4、实现一个 promise,可以让 then 方法链式调用。 ok

  • 要想实现链式调用,then方法必须返回一个promise,并且then方法接受的是一个then返回的值
  then(onFulfilled) {
          if (this.state === PENDING) {
            return new MyPromise((resolve) => {
              this.resolveCallback.push(() => {
                const x = onFulfilled(this.val)
                resolve(x)
              }) 
            })
          }
        }
        
//去掉callback的val
 this.resolveCallback.map((callBack) => {
                  callBack()
                })

5、实现一个 promise,支持空 then 函数。

  • 如果传的是一个then的空函数,上面会报错,所以我们要给onFulfilled设置一个默认值,
 then(onFulfilled=val=>val) 

6、实现一个 promise,支持 then 传递 thenable 对象。 OK

  • 如果x是个对象象或者函数把 x.then 赋值给 then
  • 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
  • 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
  • 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
  • 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
      then(onFulfilled = (val) => val, onRejected) {
          //允许传一个空的then
          if (this.state === PENDING) {
            const promise2 = new MyPromise((resolve, reject) => {
              this.resolveCallback.push(() => {
                const x = onFulfilled(this.val)
                promiseSolution(promise2, x, resolve, reject)
              })
            })
            return promise2
          }
        }
        
        
        
        function promiseSolution(promise2, x, resolve, reject) {
        if ((typeof x === 'object' || typeof x === 'function') && x != null) {
          if (x.then && typeof x.then === 'function') {
            x.then((y) => {
              //如果y也是一个thenAble对象回调即可
              resolve(y)
            })
          } else {
            resolve(x)
          }
        } else {
          resolve(x)
        }
      }

7、实现一个 promise,支持 then 传递 promise 对象(x)。

  • 如果x是请求状态(pending),promise必须保持pending直到xfulfilled或rejected
  • 如果x是完成态(fulfilled),用相同的值完成fulfillpromise
  • 如果x是拒绝态(rejected),用相同的原因rejectpromise
  if (x instanceof MyPromise) {
          if (x.state === PENDING) {
            x.then((y) => {
              //如果y也是一个thenAble对象回调即可
              promiseSolution(promise2, y, resolve, reject)
            }, reject)
          } else {
            x.state === FULFILLD && resolve(x.value)
            x.state === REJECTED && reject(x.value)
          }
        }

8、实现一个 promise,支持 resolve 传递 promise 对象。

const resolve = (val) => {
            if ((typeof val === 'object' || typeof val=== 'function') && val.then) {
              promiseSolution(this, val, resolve, reject)
              return
            }
            setTimeout(() => {
              //只允许resolve一次
              if (this.state === PENDING) {
                this.val = val
                this.state = FULFILLD //状态变为fulfilled;
                //执行所以的then方法,then可能有多个
                this.resolveCallback.map((callBack) => {
                  callBack()
                })
              }
            })
          }

9、实现一个 promise,处理 then 中的循环 promise。 ok

  • 所谓的循环promise是指在then中返回promise自身,这样会导致死循环。所以promise遇见该情况会抛出异常
//在promiseSolution中判断是否自身的条件拦截。
if(promise2===x)throw new Error('死循环');

10、实现一个 promise,支持静态方法 Promise.all。 ok -promise.all返回的是一个promise。 -所有的promise的运行成功,会返回一个数组,数组的值是所有promise返回的值 -如果有一个promise出现reject,则会reject该错误

 static all(promiseArr) {
          return new MyPromise((resolve, reject) => {
            let times = 0
            let result = []
            console.log(promiseArr)
            for (let i = 0; i < promiseArr.length; i++) {
              promiseArr[i].then(
                (res) => {
                  processResolve(res, resolve)
                },
                (err) => {
                  console.log(err)
                  reject(err)
                }
              )
            }
            function processResolve(res, resolve) {
              times++
              result.push(res)
              if (times === promiseArr.length) {
                resolve(result)
              }
            }
          })
        }

11、实现一个 promise,支持 reject 和 catch。

  const reject = (err) => {
            //状态变为reject
            setTimeout(() => {
              if (this.state === PENDING) {
                this.state = REJECTED
                this.reason = err
                this.rejectCallback.map((callBack) => {
                  callBack()
                })
              }
            })
          }
  
   this.rejectCallback.push(() => {
                const y = onRejected(this.reason)
                promiseSolution(promise2, y, resolve, reject)
              })
              
              

12、实现一个 promise,支持处理完成态或失败态的 then。

  • 上面的代码只能处理状态为pending的promise,向下面这种情况,promise已经变为fulfilled状态,所以不会打印
      if (this.state === FULFILLD) {
            promise2 = new MyPromise((resolve, reject) => {
              const x = onFulfilled(this.val)
              promiseSolution(promise2, x, resolve, reject)
            })
          }
          if (this.state === REJECTED) {
            promise2 = new MyPromise((resolve, reject) => {
              const y = onRejected(this.reason)
              promiseSolution(promise2, y, resolve, reject)
            })
          }

完整代码

   const PENDING = 'pending'
      const FULFILLD = 'fulfilled'
      const REJECTED = 'reject'
      class MyPromise {
        static all(promiseArr) {
          return new MyPromise((resolve, reject) => {
            let times = 0
            let result = []
            console.log(promiseArr)
            for (let i = 0; i < promiseArr.length; i++) {
              promiseArr[i].then(
                (res) => {
                  processResolve(res, resolve)
                },
                (err) => {
                  console.log(err)
                  reject(err)
                }
              )
            }
            function processResolve(res, resolve) {
              times++
              result.push(res)
              if (times === promiseArr.length) {
                resolve(result)
              }
            }
          })
        }
        constructor(fn) {
          this.state = PENDING //初始状态pending
          this.value = undefined //初始值为value
          this.reason = undefined
          this.resolveCallback = [] //用来存储then的回调函数;
          this.rejectCallback = []
          const resolve = (val) => {
            if (
              (typeof val === 'object' || typeof val === 'function') &&
              val.then
            ) {
              promiseSolution(this, val, resolve, reject)
              return
            }
            setTimeout(() => {
              //只允许resolve一次
              if (this.state === PENDING) {
                this.val = val
                this.state = FULFILLD //状态变为fulfilled;
                //执行所以的then方法,then可能有多个
                this.resolveCallback.map((callBack) => {
                  callBack()
                })
              }
            })
          }
          const reject = (err) => {
            //状态变为reject
            setTimeout(() => {
              if (this.state === PENDING) {
                this.state = REJECTED
                this.reason = err
                this.rejectCallback.map((callBack) => {
                  callBack()
                })
              }
            })
          }
          fn(resolve, reject)
        }
        then(
          onFulfilled = (val) => val,
          onRejected = (err) => {
            throw new error(err)
          }
        ) {
          const promise2 = null
          //允许传一个空的then
          if (this.state === PENDING) {
            promise2 = new MyPromise((resolve, reject) => {
              this.resolveCallback.push(() => {
                const x = onFulfilled(this.val)
                promiseSolution(promise2, x, resolve, reject)
              })
              this.rejectCallback.push(() => {
                const y = onRejected(this.reason)
                promiseSolution(promise2, y, resolve, reject)
              })
            })
          }
          if (this.state === FULFILLD) {
            promise2 = new MyPromise((resolve, reject) => {
              const x = onFulfilled(this.val)
              promiseSolution(promise2, x, resolve, reject)
            })
          }
          if (this.state === REJECTED) {
            promise2 = new MyPromise((resolve, reject) => {
              const y = onRejected(this.reason)
              promiseSolution(promise2, y, resolve, reject)
            })
          }
          return promise2
        }
      }

      function promiseSolution(promise2, x, resolve, reject) {
        if (promise2 === x) throw new Error('处理循环promixe,死循环')
        if (x instanceof MyPromise) {
          if (x.state === PENDING) {
            x.then((y) => {
              //如果y也是一个thenAble对象回调即可
              promiseSolution(promise2, y, resolve, reject)
            }, reject)
          } else {
            x.state === FULFILLD && resolve(x.value)
            x.state === REJECTED && reject(x.reason)
          }
        }
        if (
          (typeof x === 'object' || typeof x === 'function') &&
          x != null &&
          x.then
        ) {
          if (x.then && typeof x.then === 'function') {
            x.then((y) => {
              //如果y也是一个thenAble对象回调即可
              promiseSolution(promise2, y, resolve, reject)
            })
          } else {
            resolve(x)
          }
        } else {
          resolve(x)
        }
      }