手把手教你如何写一个Promise

Promise是一种用于处理异步操作的机制,它可以将异步操作的结果以同步的方式进行处理和返回。在JavaScript中,Promise是一种内置对象,但我们也可以手动实现一个Promise类来更好地理解其原理和工作方式。

一、Promise的特性

首先,让我们来介绍一下:

  1. Promise 有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。初始状态为 pending,当异步操作完成时,可以变为 fulfilled或 rejected
  2. Promise 具有链式调用的特性。通过then方法可以注册回调函数,在异步操作完成后执行这些回调函数。then方法返回一个新的Promise对象,使得多个异步操作可以按顺序执行。
  3. Promise可以通过resolve方法将状态从pending变为fulfilled,并传递一个值作为成功的结果;也可以通过reject方法将状态从pending变为rejected,并传递一个原因作为失败的结果。
  4. Promise可以通过catch方法捕获错误,并处理错误情况。
  5. Promise还提供了一些静态方法,如resolverejectallrace等。其中,resolve方法返回一个已经成功的Promise对象;reject方法返回一个已经失败的Promise对象;all方法接收一个包含多个Promise对象的数组,并在所有Promise对象都成功时返回一个包含所有结果的新Promise对象;race方法接收一个包含多个Promise对象的数组,并在任意一个Promise对象成功或失败时返回相应结果。

接下来,我们从源码角度讲解一下手写的Promise类。

二、手写Promise

定义常量

首先,我们定义了三个常量:PENDING表示promise的初始状态,FULFILLED表示promise成功的状态,REJECTED表示promise失败的状态。

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

定义MyPromise类

接下来,我们定义了一个MyPromise类,该类拥有以下属性:

  • state:表示promise的当前状态,默认为PENDING。
  • value:表示promise成功时的返回值,默认为undefined。
  • reason:表示promise失败时的错误原因,默认为undefined。
  • onFulfilledCallbacks:用于存储成功回调函数的数组。
  • onRejectedCallbacks:用于存储失败回调函数的数组。

构造函数(constructor)中接受一个executor函数作为参数,该函数接受两个参数:resolve和reject。我们在构造函数中定义了resolve和reject函数,并将它们传递给executor函数。如果executor函数执行成功,则调用resolve函数,如果执行失败,则调用reject函数。

class MyPromise {
  constructor(executor) {
    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []

    const resolve = (value) => {
      if (this.state = PENDING) {
        this.state = FULFILLED
        this.value = value
        this.onFulfilledCallbacks.forEach(fn => fn())
      }
    }

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.reason = reason
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }

    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
}
  1. resolve函数中,我们首先判断promise的当前状态是否为PENDING。如果是,那么将状态改为FULFILLED并将返回值赋给value属性,并依次调用成功回调数组中的回调函数。
  2. reject函数中,同样首先判断promise的当前状态是否为PENDING。如果是,那么将状态改为REJECTED并将错误原因赋给reason属性,并依次调用失败回调数组中的回调函数。
  3. 在构造函数的末尾,通过try-catch语句执行executor函数。如果执行过程中有错误抛出,那么调用reject函数将错误原因赋给reason属性。

resolve和reject

接下来是resolve和reject方法的实现。resolve方法将状态从pending变为fulfilled,并传递一个值作为成功的结果;reject方法将状态从pending变为rejected,并传递一个原因作为失败的结果。

static resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value)
    })
}

static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason)
    })
}

then

  • 在then方法中,我们创建了一个新的MyPromise实例promise2,并在其构造函数中定义了resolve和reject函数。

  • 根据当前promise的状态,分别处理不同的情况:

    • 如果当前状态是PENDING,那么将onFulfilled和onRejected回调函数分别推入onFulfilledCallbacks和onRejectedCallbacks数组中。
    • 如果当前状态是FULFILLED,那么异步地执行onFulfilled回调,并根据返回值调用resolve或reject函数。
    • 如果当前状态是REJECTED,那么异步地执行onRejected回调,并根据返回值调用resolve或reject函数。
  • 最后,返回promise2实例。

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = function (value) {
        return value
      }
    }

    if (typeof onRejected !== 'function') {
      onRejected = function (reason) {
        throw reason
      }
    }

    let promise2 = new MyPromise((resolve, reject) => {
      switch (this.state) {
        case PENDING:
          this.onFulfilledCallbacks.push(() => {
            setTimeout(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (err) {
                reject(err)
              }
            }, 0)
          })
          this.onRejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                const value = onRejected(this.reason)
                resolve(value)
              } catch (err) {
                reject(err)
              }
            }, 0)
          })
          break
        case FULFILLED:
          setTimeout(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (err) {
              reject(err)
            }
          }, 0)
          break
        case REJECTED:
          setTimeout(() => {
            try {
              const value = onRejected(this.reason)
              resolve(value)
            } catch (err) {
              reject(err)
            }
          }, 0)
          break
      }
    })
    return promise2
  }

catch和finally

  1. catch方法是then方法的一个语法糖,用于捕获promise链中的错误。它接受一个参数onRejected,表示失败的回调函数,然后调用then方法,并将onRejected作为第二个参数传入。
  2. finally方法是then方法的另一个语法糖,无论promise的状态是成功还是失败,都会执行finally方法中的回调函数。它接受一个参数fn,并在then方法中通过两个回调函数分别调用fn,并根据返回值执行resolve或reject函数
  catch(onRejected) {
    return this.then(null, onRejected)
  }

  finally(fn) {
    return this.then(
      (value) => {
        fn()
        return value
      },
      (reason) => {
        fn()
        throw reason
      }
    )
  }

all和race

  • all方法接受一个promise数组作为参数,返回一个新的MyPromise实例。当所有 promise 都成功时,返回一个包含所有成功值的数组;否则,返回一个包含第一个失败的 promise 的错误原因的新的 MyPromise 实例。
  • race方法接受一个promise数组作为参数,返回一个新的MyPromise实例。当任何一个promise成功时,返回该成功的promise的值;否则,返回第一个失败的promise的错误原因的新的MyPromise实例。
  static all(promises) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        resolve([])
      } else {
        let result = []
        for (let i = 0;i < promises.length; i++) {
          promises[i].then(
            data => {
              result[i] = data
              if (result.length === promises.length) {
                resolve(result)
              }
            },
            err => {
              reject(err)
              return
            }
          )
        }
      }
    })
  }

  static race(promises) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        resolve()
      } else {
        for (let i = 0; i < promises.length; i++) {
          promises[i].then(
            data => {
              resolve(data)
            },
            (err) => {
              reject(err)
              return
            }
          )
        }
      }
    })
  }

三、完整版MyPromise

const PENDING = 'pending'  // 声明一个常量PENDING,表示Promise的初始状态
const FULFILLED = 'fulfilled'  // 声明一个常量FULFILLED,表示Promise的成功状态
const REJECTED = 'rejected'  // 声明一个常量REJECTED,表示Promise的失败状态

class MyPromise {
  constructor(executor) {
    this.state = PENDING  // 初始化Promise的状态为PENDING
    this.value = undefined  // 初始化Promise的值为undefined
    this.reason = undefined  // 初始化Promise的失败原因为undefined
    this.onFulfilledCallbacks = []  // 存储Promise成功状态下的回调函数
    this.onRejectedCallbacks = []  // 存储Promise失败状态下的回调函数

    // 定义resolve函数,用于将Promise状态改为FULFILLED,并执行成功状态下的回调函数
    const resolve = (value) => {
      if (this.state = PENDING) {
        this.state = FULFILLED  // 将Promise状态改为FULFILLED
        this.value = value  // 存储Promise成功时的值
        this.onFulfilledCallbacks.forEach(fn => fn())  // 执行所有成功状态下的回调函数
      }
    }

    // 定义reject函数,用于将Promise状态改为REJECTED,并执行失败状态下的回调函数
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED  // 将Promise状态改为REJECTED
        this.reason = reason  // 存储Promise失败时的原因
        this.onRejectedCallbacks.forEach(fn => fn())  // 执行所有失败状态下的回调函数
      }
    }

    try {
      executor(resolve, reject)  // 执行executor函数,并传入resolve和reject参数
    } catch (err) {
      reject(err)  // 捕获错误,并将Promise状态改为REJECTED
    }
  }

  // 静态方法resolve,返回一个状态为FULFILLED的Promise实例
  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value)
    })
  }

  // 静态方法reject,返回一个状态为REJECTED的Promise实例
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason)
    })
  }

  // 静态方法all,接收一个包含多个Promise实例的数组,返回一个新的Promise实例
  static all(promises) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        resolve([])  // 如果传入的数组为空,则直接返回一个状态为FULFILLED的Promise实例
      } else {
        let result = []  // 存储每个Promise实例的执行结果
        for (let i = 0;i < promises.length; i++) {
          promises[i].then(
            data => {
              result[i] = data  // 将每个Promise实例的执行结果存入result数组中
              if (result.length === promises.length) {
                resolve(result)  // 当所有Promise实例都执行完毕时,返回包含所有结果的新的Promise实例
              }
            },
            err => {
              reject(err)  // 如果其中一个Promise实例执行失败,则将新的Promise实例的状态改为REJECTED,并返回失败原因
              return
            }
          )
        }
      }
    })
  }

  // 静态方法race,接收一个包含多个Promise实例的数组,返回一个新的Promise实例
  static race(promises) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        resolve()  // 如果传入的数组为空,则直接返回一个状态为FULFILLED的Promise实例
      } else {
        for (let i = 0; i < promises.length; i++) {
          promises[i].then(
            data => {
              resolve(data)  // 返回第一个执行完毕的Promise实例的结果
            },
            (err) => {
              reject(err)  // 如果其中一个Promise实例执行失败,则将新的Promise实例的状态改为REJECTED,并返回失败原因
              return
            }
          )
        }
      }
    })
  }

  // then方法,用于在Promise的成功和失败状态下执行回调函数,返回一个新的Promise实例
  then(onFulfilled, onRejected) {
    // 如果onFulfilled不是一个函数,则将其更改为返回接收到的值的函数
    if (typeof onFulfilled !== 'function') {
      onFulfilled = function (value) {
        return value
      }
    }

    // 如果onRejected不是一个函数,则将其更改为抛出接收到的原因的函数
    if (typeof onRejected !== 'function') {
      onRejected = function (reason) {
        throw reason
      }
    }

    let promise2 = new MyPromise((resolve, reject) => {
      switch (this.state) {
        // 如果Promise当前的状态是PENDING,则将回调函数添加到对应的回调数组中
        case PENDING:
          this.onFulfilledCallbacks.push(() => {
            setTimeout(() => {
              try {
                const value = onFulfilled(this.value)
                resolve(value)
              } catch (err) {
                reject(err)
              }
            }, 0)
          })
          this.onRejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                const value = onRejected(this.reason)
                resolve(value)
              } catch (err) {
                reject(err)
              }
            }, 0)
          })
          break
        // 如果Promise当前的状态是FULFILLED,则直接执行成功回调函数
        case FULFILLED:
          setTimeout(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (err) {
              reject(err)
            }
          }, 0)
          break
        // 如果Promise当前的状态是REJECTED,则直接执行失败回调函数
        case REJECTED:
          setTimeout(() => {
            try {
              const value = onRejected(this.reason)
              resolve(value)
            } catch (err) {
              reject(err)
            }
          }, 0)
          break
      }
    })
    return promise2
  }

  // catch方法,用于捕获Promise的失败状态,并执行回调函数
  catch(onRejected) {
    return this.then(null, onRejected)
  }

  // finally方法,无论Promise状态是成功还是失败,都会执行回调函数
  finally(fn) {
    return this.then(
      (value) => {
        fn()
        return value
      },
      (reason) => {
        fn()
        throw reason
      }
    )
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值