手写promise(一) ——结构设计和then方法

82 阅读2分钟

一、结构设计注意事项

1.使用executor函数来控制promise的状态:当异步操作完成后再调用resolve/reject函数

2.resolve/reject函数中,只有状态为”pending"时,才可以修改状态为fullfilled/rejected。

二、then方法注意事项

1.promise状态变为fullfilled/rejected的时候,调用onFullfilled/onRejected函数,处理成功/失败的情况

2.异步操作完成==》调用resolve函数===》修改状态为fullfilled===》调用onFullfilled函数过程中出现一个问题:then函数还没调用,直接调用的onFullfilled函数,会出错。

解决上述问题方法:setTimeout/queueMicrotask都可以,二者都可以延迟执行。因为promise.then是微任务,此处选择后者。

3.实现多次调用then方法的功能:通过创建一个onFullfilledFns/onRejectedFns数组,然后每当onFullfilled/onRejected函数调用一次,都将其push到数组中,然后在resolve函数中遍历onFullfilledFns/onRejectedFns数组。

4.实现链式调用功能:返回一个新的promise

5.解决延迟调用不执行的问题:在then函数中加一个判断条件,如果状态改变且函数不为空,就去执行。

 if (this.status === FULFILLED && onFullfilled) {
            tryCatchFunction(onFullfilled, this.value, resolve, reject)
            // try {
            //   const value = onFullfilled(this.value)
            //   resolve(value)
            // }catch(error) {
            //   reject(error)
            // }
          }

          if (this.status === REJECTED && onRejected) {
            tryCatchFunction(onRejected, this.reason, resolve, reject)
            // try {
            //   const reason = onRejected(this.reason)
            //   resolve(reason)
            // }catch(error) {
            //   reject(error)
            // }
          }

6.如果是onRejected的返回值===》调用resolve函数;

如果是throw new Error() ===》调用rejected函数。

三、手写代码


    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'

    //工具函数try……catch 
    function tryCatchFunction(callBackFn, value, resolve, reject) {
      try {
        const result = callBackFn(value)
        resolve(result)
      } catch (error) {
        reject(error)
      }
    }

    class ownPromise {
      constructor(executor) {
        this.status = PENDING
        this.value = undefined
        this.reason = undefined
        this.onFullfilledFns = []
        this.onRejectedFns = []

        const resolve = (value) => {
          if (this.status === PENDING) {

            queueMicrotask(() => {
              if (this.status !== PENDING) return
              this.status = FULFILLED
              this.value = value
              this.onFullfilledFns.forEach((fn) => {
                fn(this.value)
              })
            })
          }

        }

        const reject = (reason) => {
          if (this.status === PENDING) {

            queueMicrotask(() => {
              if (this.status !== PENDING) return
              this.status = REJECTED
              this.reason = reason
              this.onRejectedFns.forEach((fn) => {
                fn(this.reason)
              })
            })
          }
        }

        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }

      }

      then(onFullfilled, onRejected) {

        return new ownPromise((resolve, reject) => {

      // 1.如果在then调用的时候, 状态已经确定下来
          if (this.status === FULFILLED && onFullfilled) {
            tryCatchFunction(onFullfilled, this.value, resolve, reject)
            // try {
            //   const value = onFullfilled(this.value)
            //   resolve(value)
            // }catch(error) {
            //   reject(error)
            // }
          }

          if (this.status === REJECTED && onRejected) {
            tryCatchFunction(onRejected, this.reason, resolve, reject)
            // try {
            //   const reason = onRejected(this.reason)
            //   resolve(reason)
            // }catch(error) {
            //   reject(error)
            // }
          }
      // 2.将成功回调和失败的回调放到数组中

          if (this.status === PENDING) {
            this.onFullfilledFns.push(() => {
              tryCatchFunction(onFullfilled, this.value, resolve, reject)

              // try {
              // const value = onFullfilled(this.value) 
              // resolve(value)
              // }catch (error) {
              //   reject(error)
              // }
            })

            this.onRejectedFns.push(() => {
              tryCatchFunction(onRejected, this.reason, resolve, reject)

              // try {
              //   const reason = onRejected(this.reason)
              //   resolve(reason)
              // } catch(error) {
              //   reject(error)
              // }
            })
          }

        })
      }

    }
// ------------------测试代码------------------------

const myPromise = new ownPromise((resolve, reject) => {
  // resolve("我是value")
  reject("我是reason")
  // throw new Error("抛出一个异常")
})

//测试多次调用

myPromise.then(res => {
  console.log("res1", res)
  return "我是第一次调用then函数中resolve函数的返回值"
}, err => {
  console.log("err1", err)
  return "我是第一次调用then函数中reject函数的返回值"
}).then(res => {
  console.log("res2", res)
}, err => {
  console.log("err2", err)
})