手写promise

176 阅读3分钟

1.什么是promise?promise解决了什么问题?

Promise是 JavaScript 中处理异步操作的一种机制,它可以让异步操作更加可控、易于管理。 在 JavaScript 中,许多操作都是异步的,比如网络请求、读取文件等。异步操作通常会导致代码变得复杂,因为你需要正确地处理回调函数,处理错误等等。为了解决这个问题,Promise 在 ECMAScript 6 (ES6) 中被引入。

  1. 顺序控制:使用 Promise,你可以通过 then 方法按照顺序执行异步操作,使得代码的执行流程更加清晰,而不需要嵌套多层的回调函数(这也被称为“回调地狱”)。
  2. 错误处理:Promise 提供了 catch 方法,可以用来统一处理异步操作中发生的错误,避免错误冒泡到全局作用域。
  3. 避免回调地狱:Promise 可以解决传统的回调函数嵌套问题,让代码更易于理解和维护。
  4. 更容易的异步编程:使用 Promise,你可以更容易地组织和管理异步代码,可以使用 Promise.all 和 Promise.race 来处理多个异步操作,以及进行并发控制等等。
  5. 更容易进行错误处理和调试:Promise 提供了明确的错误处理机制,让你可以很容易地找到并解决异步操作中的问题。
// 定义promise状态常量
const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
  // 声明私有属性 #
  #state = PENGDING
  #result = undefined
  #hanlders = []
  constructor(executor) {
    // 调用对应函数改变状态,初始状态为pending
    // promise的状态一但改变就是不可再变的了
    const resolve = (data) => {
      //   if (this.#state !== PENGDING) return
      //   this.#state = FULFILLED
      //   this.#result = data
      this.#changeState(FULFILLED, data)
    }
    const reject = (reason) => {
      //   if (this.#state !== PENGDING) return
      //   this.#state = REJECTED
      //   this.#result = reason
      this.#changeState(REJECTED, reason)
    }
    // promise 无法捕获异步错误
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  #changeState(state, result) {
    if (this.#state !== PENGDING) return
    this.#state = state
    this.#result = result
    console.log(this.#state, this.#result)
    // 当promise状态改变执行run
  }

  // 接收两个回调,一个失败的回调,一个成功的回调
  // then方法返回的还是一个promise
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#hanlders.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      })
      this.#run()
    })
  }

  catch(onRejected) {
    return this.then(null, onRejected)
  }

  #isPromiseAPlus(obj) {
    return (
      typeof obj === 'object' &&
      obj !== null &&
      typeof obj.then === 'function' &&
      typeof obj.catch === 'function'
    )
  }

  // 使用 setTimeout 来模拟微任务,确保了异步任务的执行
  #runMicroTask(func) {
    setTimeout(func, 0)
  }

  #runOne(callback, resolve, reject) {
    this.#runMicroTask(() => {
      if (typeof callback !== 'function') {
        const settled = this.#state === FULFILLED ? resolve : reject
        settled(this.#result)
        return
      }
      try {
        const data = callback(this.#result)
        if (this.#isPromiseAPlus(data)) {
          data.then(resolve, reject)
        } else {
          resolve(data)
        }
      } catch (error) {
        reject(error)
      }
    }, 0)
  }

  #run() {
    if (this.#state === PENGDING) return
    // 当前promise状态===FULFILLED
    while (this.#hanlders.length) {
      const { onFulfilled, onRejected, resolve, reject } =
        this.#hanlders.shift()
      /**
       * 1.什么时候该调用resolve,reject?有以下三种情况
       *  对应的回调不是函数
       *  回调是函数
       *  回调是promise
       */
      if (this.#state === FULFILLED) {
        this.#runOne(onFulfilled, resolve, reject)

        // if (typeof onFulfilled === 'function') {
        //   // 当回调是函数时,try catch 捕获错误
        //   try {
        //     const data = onFulfilled(this.#result)
        //     resolve(data)
        //   } catch (error) {
        //     reject(error)
        //   }
        // } else {
        //   // 当回调不是函数时,promise执行穿透
        //   resolve(this.#result)
        // }
      } else if (this.#state === REJECTED) {
        this.#runOne(onRejected, resolve, reject)

        // if (typeof onRejected === 'function') {
        //   // 当回调是函数时,try catch 捕获错误
        //   try {
        //     const data = onRejected(this.#result)
        //     resolve(data)
        //   } catch (error) {
        //     reject(error)
        //   }
        // } else {
        //   // 当回调不是函数时,promise执行穿透
        //   reject(this.#result)
        // }
      }
    }
  }
}

let myPromise = new MyPromise((resolve, reject) => {
  resolve('123')
})

myPromise.then((res) => {
  console.log(res)
})

myPromise.then((res) => {
  console.log(res)
})

myPromise
  .then(null, (err) => {
    console.log(err)
  })
  .then((data) => {
    console.log('data', data)
  })

2.以上部分代码来自于袁进老师

此篇文章仅用于个人知识点记录。袁老师个人blog: blog.yuanjin.tech/