手写promise

61 阅读3分钟

当我们看到这个问题时我们就要想起来什么是promise,promsie该怎么用,解决什么问题的

认识promise

Promise 是 JavaScript 中用于处理异步操作的一种机制。它代表一个异步操作的最终完成(或失败)及其结果值。Promise 的主要目的是解决传统的回调地狱(Callback Hell)问题,使异步代码更易读、更易维护。

promise的用法

既然我们已经知道了promsie是什么,接下来我们来看看promsie该怎么用

function A() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
     console.log("A");
      resolve()  
    }, 1000);
  })
}

function B() {
  console.log("B");
}


A()
.then(() => {  
   B() 
})

这段代码很简单,打印结果为A B如果没有promise,根据事件循环机制,耗时代码分为微任务和宏任务,先执行同步代码再执行异步代码,所以B会先A打印.有了promise,可以通过resolve, reject改变promsie对象的pending状态,状态改变再后再执行.then内的函数.注意resolve()和rejecte()里是可以带参数的

一个 Promise 对象有三种状态:

  1. Pending(进行中) :初始状态,既不是成功,也不是失败。
  2. Fulfilled(已成功) :表示操作成功完成。
  3. Rejected(已失败) :表示操作失败。

一旦 Promise 的状态从 Pending 变为 Fulfilled 或 Rejected,就不会再改变。

Promise 对象有两个主要方法:

  • .then() :用于处理 Fulfilled 状态的结果。
  • .catch() :用于处理 Rejected 状态的错误。

手写promise

class MyPromise {
    constructor(executor) {
      this.status = 'pending'  // 状态
      this.value = null  // 成功的结果
      this.reason = null  // 失败的结果
      this.onFulfilledCallbacks = []  // 存放成功的回调函数
      this.onRejectedCallbacks = []  // 存放失败的回调函数
  
      const resolve = (value) => {
        if (this.status === 'pending') {
          this.value = value
          this.status = 'fulfilled'
          this.onFulfilledCallbacks.forEach(fn => fn(value))
        }
      }
      const reject = (reason) => {
        if (this.status === 'pending') {
          this.reason = reason
          this.status = 'rejected'
          this.onRejectedCallbacks.forEach(fn => fn(reason))
        }
      }
  
      executor(resolve, reject)
    }
    then(onFulfilled, onRejected) {
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
      onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
  
      // 返回一个新的promise对象
      let newPromise = new MyPromise((resolve, reject) => {
        if (this.status === 'fulfilled') {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value) // 作为异步任务
              if (result instanceof MyPromise) {
                newPromise = result
              } 
              resolve(result)
            } catch (error) {
              reject(error)
            }
            
          });
        }
        if (this.status === 'rejected') {
          setTimeout(() => {
            try {
              const result = onRejected(this.reason) // 作为异步任务
              if (result instanceof MyPromise) {
                newPromise = result
              } 
              resolve(result)
            } catch (error) {
              reject(error)
            }
            
          });
        }
       if (this.status === 'pending') {
          this.onFulfilledCallbacks.push((value) => {
            setTimeout(() => {
              try {
                const result = onFulfilled(value)
                if (result instanceof MyPromise) {
                  newPromise = result
                }
                resolve(result)
              } catch (error) {
                reject(error)
              }
            })
          })
          this.onRejectedCallbacks.push((reason) => {
           setTimeout(() => {
              try {
                const result = onRejected(reason)
                if (result instanceof MyPromise) {
                  newPromise = result
                }
                resolve(result)
              } catch (error) {
                reject(error)
              }
            })
          })
        }
      })
      return newPromise
    }
  }

首先new promise中要接受一个回调函数作为参数放到构造器中,初始状态为pending,又因为resolve和reject可以传参,this.value = null 和this.reason = null 分别存结果.this.onFulfilledCallbacks = [] , this.onRejectedCallbacks = [] 分别存回调结果.resolve和reject函数就很简单,将promise对象的状态进行变更,再执行数组中的回调函数.

then函数和catch函数:

then的原理:

  1. 接收两个参数,一个是成功的回调函数,另一个是失败的回调函数
  2. 返回一个promise对象
  3. 当执行到then的时候,then前面的promise状态已经变更为fulfilled或rejected,则会立即执行then中的回调函数
  4. 当执行到then的时候,then前面的promise状态还是pending,则会将回调函数存储起来,等到前面promise的状态变更为fulfilled或rejected时,再执行回调函数

then其实是可以接受两个参数(都是函数),第二个就是catch的功能. 先进行类型判断,如果进来的参数是函数体就不做修改,如果不是就放一个没意义的函数体.Rejected是会报错的所以要抛出错误;因为then后面还开会接.then所以也要返回一个promise对象.在里面判断第一个函数的状态(通过隐式绑定规则);接下来就是要将then里面的函数进行调用了;但是如果直接调用就是当做同步任务触发,根据事件循环机制是要把.then当中异步任务触发;所以我们用同为异步任务的定时器来包裹一下.还有我们要考虑.then()里面的函数是否有返回对象,如果有返回对象且返回的是promise对象,我们就要返回它自己的promise对象.