javascirpt手写promise原理由浅入深

js手写Promise原理

前言

如果手写了promise那么,会对你有以下帮助
1,js功底更加深厚
2,有助于读懂大佬们的源码
3,熟练使用promise,你想你都把原理搞明白了那么使用个api还不得心应手
4,有助于面试,面试官常问
了解promise
1,Promise是一个类,可以翻译成承诺、许诺、期约。
2,Promise的状态一旦被确定下来,无法被更改,resolve、reject两个回调函数同时存在只能执行一个,那个在前执行那个。
3,Promise的三个状态
待定( pending ) : 初始状态,既没有被兑现,也没有被拒
已兑现( fulfilled ) : 意味着操作已经完成 resolve
已拒绝 (rejected):意味着操作失败 reject

promise初步基本结构

我们先初步搭建结构
1,我们新建一个HFPromise构造函数,HFPromise当中有一个函数被当做参数传递,且这个函数又有两个参数resolve与reject也是函数。

const promise = new HFPromise((resolve, reject) => {
  debugger
  // reject('111')
  resolve('222')
})

那么我们的类应该这样写
1,promise穿过来一个参数executor为函数,这个函数立即执行,这个函数中有两个参数resolve与reject也是函数,所以我们要在类里创建方法,将resolve与reject在executor执行时传回去
2,我们知道promise是有三个状态的,所以我们要定义三个状态,用来判断。因为我们resolve成功和reject失败只能调一个不可能同时存在

3,我们知道resolve执行的时候是有参数的,例如resolve(‘222’),那么我们在类里创建的resolve方法要带接受222值,并保存下来

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined

        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            this.status = PROMISE_STATUS_FULFILLED
            console.log('res');
            this.value = value
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            this.status = PROMISE_STATUS_REJECTED
            console.log("rej");
            this.reason = reason
          }
        }
        executor(resolve, reject)
      }
    }

promise的then方法

1,在类里新建then方法,then方法中有两个箭头函数成功与失败,所以我们用参数接受一下这两个函数,并将其push到对应的数组中
2,调用多次then()应该都被执行,所以创两个数组一个成功一个失败,用来遍历执行
3,queueMicrotask是微任务,js是单线程的,但是怎么异步的呢。浏览器事件循环中,先执行顶层代码再执行完微任务队列后再执行宏任务队列。与栈相反,先加入队列的先执行。
宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()

    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledFNs = []
        this.onRejectedFns = []
        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_FULFILLED
              console.log('res');
              this.value = value
              this.onFulfilledFNs.forEach(fn => {
                fn(this.value)
              })
            })
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_REJECTED
              console.log("rej");
              this.reason = reason
              this.onRejectedFns.forEach(fn => {
                fn(this.reason)
              })
            })
          }
        }
        executor(resolve, reject)
      }
      then(onFulfilled, onRejected) {
        if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
          debugger
          onFulfilled(this.value)
        }
        if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
          onRejected(this.reason)
        }
        if (this.status === PROMISE_STATUS_PENDING) {
          debugger
          this.onFulfilledFNs.push(onFulfilled)
          this.onRejectedFns.push(onRejected)
        }
        // this.onFulfilledFNs.push(onFulfilled)
        // this.onRejectedFns.push(onRejected)
      }
    }

    const promise = new HFPromise((resolve, reject) => {
      debugger
      // reject('111')
      resolve('222')
    })

    // 调用两次then()应该都被执行,所以创两个数组一个成功一个失败,便利执行
    promise.then(res => {
      debugger
      console.log(res);
    }, err => {
      console.log(err);
    })

    promise.then(res => {
      debugger
      console.log(res);
    }, err => {
      console.log(err);
    })
    //这里在延迟执行时,promise中onFulfilledFNs 和onRejectedFns数组已经添加完毕,去执行了
    // 所以这边没办法执行,所以我们要根据状态判断直接执行这两个回调函数
    setTimeout(() => {
      promise.then(res => {
        console.log(res);
      }, err => {
        console.log(err);
      })
    }, 1000)

promise的then方法链式调用

1,链式调用说明,then返回的是promise,所以我们改进一下then方法
2,then链式调用中上一个then的返回值是下一个then的成功值,并执行成功函数代码块 所以我们用try catch包裹
3,then链式调用中上一个then抛出异常是下一个then的失败值执行,并执行失败函数代码块 所以我们用try catch包裹
4,如果你在第一个promise中就抛出了异常那么我们也要将executor(resolve, reject)用try catch包裹

  const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledFNs = []
        this.onRejectedFns = []
        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_FULFILLED
              console.log('res');
              this.value = value
              this.onFulfilledFNs.forEach(fn => {
                fn(this.value)
              })
            })
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_REJECTED
              console.log("rej");
              this.reason = reason
              this.onRejectedFns.forEach(fn => {
                fn(this.reason)
              })
            })
          }
        }
        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {


        return new Promise((resolve, reject) => {
          if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
            debugger
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_PENDING) {
            debugger
            this.onFulfilledFNs.push(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (error) {
                reject(error)
              }
            })
            this.onRejectedFns.push(() => {
              try {
                const reason = onRejected(this.reason)
                resolve(reason)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }

    }

    const promise = new HFPromise((resolve, reject) => {
      debugger
      reject('111')
      // resolve('222')
      // throw new Error('message err----')
    })
    promise.then(res => {
      debugger
      console.log("res1", res);
      // return "aaa"
    }, err => {
      console.log("err1", err);
      return "bbb"
      // throw new Error('message err')
    }).then(res => {
      console.log("res2", res);
    }, err => {
      console.log("err2", err);
    })

promise的的catch方法

1, .catch是接在then后面的,then返回的是一个新promise,所以你在把错误传到then的时候,将会给到新的promise赋值
2,如何解决呢,我们在then里面做个判断,如果为空,则抛出异常,我们上面链式调用时已经测试了,err1抛出的异常,在err2打印
3,还有个小问题,你要判断onFulfilled是否有值,有值在push到数组中,这里我们用不到他,他是undifaned
promise1 undefined
promise2 err => {}
reject会去调第一个,但第一个是undefind 异常被加到第二个新promise里面了。第一个promise如何用第二个promise的异常?第一个抛出异常第二就接收异常就可以执行了

    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledFNs = []
        this.onRejectedFns = []
        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_FULFILLED
              console.log('res');
              this.value = value
              this.onFulfilledFNs.forEach(fn => {
                fn(this.value)
              })
            })
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_REJECTED
              console.log("rej");
              this.reason = reason
              this.onRejectedFns.forEach(fn => {
                fn(this.reason)
              })
            })
          }
        }
        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {
        onRejected = onRejected || (err => { throw err })
        return new Promise((resolve, reject) => {
          if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
            debugger
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_PENDING) {
            debugger
            if (onFulfilled) this.onFulfilledFNs.push(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (error) {
                reject(error)
              }
            })
            if (onRejected) this.onRejectedFns.push(() => {
              try {
                const reason = onRejected(this.reason)
                resolve(reason)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
      catch(onRejected) {
        this.then(onFulfilled, onRejected)
      }
    }

    const promise = new HFPromise((resolve, reject) => {
      debugger
      // reject('111')
      resolve('222')
      // throw new Error('message err----')
    })
    // 链式调用
    //1返回promise
    //2 res1 err1返回的值 res2 err2打印
    //3. res1 err1 抛出异常 res2 err2打印
    //4. HFPromise抛出异常,err1打印
    // promise.then(res => {
    //   debugger
    //   console.log("res1", res);
    //   // return "aaa"
    // }, err => {
    //   console.log("err1", err);
    //   // return "bbb"
    //   throw new Error('message err')
    // }).then(res => {
    //   console.log("res2", res);
    // }, err => {
    //   console.log("err2", err);
    // })



    //1,.catch是接在then后面的,then返回的是一个新promise,所以你在把错误传到then的时候,将会给到新的promise赋值
    //2,如何解决呢,我们在then里面做个判断,如果为空,则抛出异常,我们上面链式调用时已经测试了,err1抛出的异常,在err2打印
    //3,还有个小问题,你要判断onFulfilled是否有值,有值在push到数组中,这里我们用不到他,他是undifaned
    // promise1 undefined
    // promise2 err => {}
    //  reject会去调第一个,但第一个是undefind  异常被加到第二个新promise里面了。第一个promise如何用第二个promise的异常?第一个抛出异常第二就接收异常就可以执行了

    promise.then(res => {
      console.log(res);
    }).catch(err => {
      console.log("caerr", err);
    })

promise的resolve与reject方法

类里加成功和失败方法,这是promise自己的方法所以static

      static resolve(value) {
        return new HFPromise((resolve) => resolve(value))
      }
      static reject(reason) {
        return new HFPromise((reject) => reject(reason))
      }

调用

    HFPromise.resolve('hello,world').then((res) => {
      console.log(res);
    })
    HFPromise.reject('massage-err').then(err => {
      console.log(err);
    })

promise的finally方法

    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledFNs = []
        this.onRejectedFns = []
        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_FULFILLED
              console.log('res');
              this.value = value
              this.onFulfilledFNs.forEach(fn => {
                fn(this.value)
              })
            })
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_REJECTED
              console.log("rej");
              this.reason = reason
              this.onRejectedFns.forEach(fn => {
                fn(this.reason)
              })
            })
          }
        }
        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {
        onRejected = onRejected || (err => { throw err })
        return new Promise((resolve, reject) => {
          if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
            debugger
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_PENDING) {
            debugger
            if (onFulfilled) this.onFulfilledFNs.push(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (error) {
                reject(error)
              }
            })
            if (onRejected) this.onRejectedFns.push(() => {
              try {
                const reason = onRejected(this.reason)
                resolve(reason)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
      catch(onRejected) {
        this.then(onFulfilled, onRejected)
      }
      //不管成功或失败都要调finakky
      finally(onFinally) {
        this.then(() => {
          onFinally()
        }, () => {
          onFinally()
        })
      }
    }

    const promise = new HFPromise((resolve, reject) => {
      debugger
      reject('111')
      // resolve('222')
      // throw new Error('message err----')
    })


    promise.then(res => {
      console.log(res);
      return 'aaaa'
    }).then(res => {
      console.log('res2', res);
      return 'aaaa'
    }).catch((err) => {
      console.log('err', err);
    }).finally(() => {
      console.log('finally--');
    })

promise的all方法

比较简单,认真阅读就看懂了,如果then链式调用搞懂其他都相对简单

    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class HFPromise {
      constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledFNs = []
        this.onRejectedFns = []
        const resolve = (value) => {
          debugger
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_FULFILLED
              console.log('res');
              this.value = value
              this.onFulfilledFNs.forEach(fn => {
                fn(this.value)
              })
            })
          }
        }
        const reject = (reason) => {
          if (this.status === PROMISE_STATUS_PENDING) {
            queueMicrotask(() => {
              if (this.status !== PROMISE_STATUS_PENDING) return
              this.status = PROMISE_STATUS_REJECTED
              console.log("rej");
              this.reason = reason
              this.onRejectedFns.forEach(fn => {
                fn(this.reason)
              })
            })
          }
        }
        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {
        onRejected = onRejected || (err => { throw err })
        return new Promise((resolve, reject) => {
          if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
            debugger
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          }
          if (this.status === PROMISE_STATUS_PENDING) {
            debugger
            if (onFulfilled) this.onFulfilledFNs.push(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (error) {
                reject(error)
              }
            })
            if (onRejected) this.onRejectedFns.push(() => {
              try {
                const reason = onRejected(this.reason)
                resolve(reason)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
      catch(onRejected) {
        this.then(onFulfilled, onRejected)
      }
      //不管成功或失败都要调finakky
      finally(onFinally) {
        this.then(() => {
          onFinally()
        }, () => {
          onFinally()
        })
      }
      static resolve(value) {
        return new HFPromise((resolve) => resolve(value))
      }
      static reject(reason) {
        return new HFPromise((reject) => reject(reason))
      }
      static all(arr) {
        return new HFPromise((resolve, reject) => {
          const promiseARR = []
          arr.forEach(promise => {
            promise.then(res => {
              promiseARR.push(res)
              if (promiseARR.length === arr.length) {
                resolve(promiseARR)
              }
            }, err => {
              reject(err)
            })
          })
        })
      }
    }
    const p1 = new promise(resolve => {
      setTimeout(() => {
        console.log('111');
      }, 1000)
    })
    const p2 = new promise(resolve => {
      setTimeout(() => {
        console.log('222');
      }, 2000)
    })
    const p3 = new promise(resolve => {
      setTimeout(() => {
        console.log('333');
      }, 3000)
    })


    HFPromise.all([p1, p2, p3]).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值