自己实现一个Promise

10次阅读

共计 2487 个字符,预计需要花费 7 分钟才能阅读完成。

最近看到好多讲解 Promise 源码解析,或者自己实现一个 Promise 的文章,突然想自己造个轮子试一试。

先说明一下,该轮子并不完全遵守任何标准和规范,只是对正规 Promise 使用后的理解和感受而编写的,纯属兴趣研究。

下面是实现代码:


// 对象类型判断
const is = (typeAsString) => obj => Object.prototype.toString.call(obj) === typeAsString

// 判断是否为一个 Error 对象
const isError = is('[object Error]')


/**
 * 自定义 Promise 对象
 * @param {(resolve: (value: any) => void, reject: (reason: any) => void) => void} executor 
 */
function MyPromise(executor) {
  this.executor = executor
  // 初始状态为 pending...
  this.status = 'pending'

  /**
   * 内部判定状态,只有处于 pending 状态才可继续执行
   * @param {number} value 
   */
  function resolve(value) {if (this.status === 'pending') { // 确保只执行一次
      this.onfulfilled = ___onfulfilled.call(this, value)
    }
  }

  /**
   * 为了缓存 resolve 方法的执行结果
   * @param {*} value value 就是 resolve 方法的执行结果
   */
  function ___onfulfilled(value) {
    this.status = 'fulfilled'   // 更改内部状态
    /**
     * @param {(value: number) => void} onfulfilled 这里是 then 方法中传入的参数
     */
    return (onfulfilled) => {return onfulfilled(value) // 
    }
  }

  /**
   * 触发异常的方法
   * @param {string} reason 
   */
  function reject(reason) {if (this.status === 'pending') {  // 确保只执行一次
      this.onrejected = ___onrejected.call(this, reason)
    }
  }

  /**
   * 
   * @param {Error} reason 如果传入的不是一个 Error 对象,那么会使用 Error 包装一下
   */
  function ___onrejected(reason) {
    this.status = 'rejected'    // 更改内部状态
    return (onrejected) => {reason = isError(reason) ? reason : new Error(reason)
      return onrejected(reason)
    }
  }


  /**
   * @param {(value: number) => any} onfulfilled 处理成功的函数
   * @param {(reason: any) => void} onrejected 处理出现异常的函数,如果传入该参数,那么 catch 方法就捕获不到了
   */
  this.then = function(onfulfilled, onrejected) {
    const self = this
    return new MyPromise((resolve, reject) => {setTimeout(function waitStatus() {switch (self.status){
          case 'fulfilled': // resolved
            if (onfulfilled) {
              // 将 onfulfilled 方法的返回值交给 resolve,确保下一个.then 方法能够得到上一个.then 方法的返回值
              const nextValue = self.onfulfilled(onfulfilled) 
              resolve(nextValue)
            } else {resolve()   // 没有传入参数,假装传入了参数:)
            }
            break
          case 'rejected':  // rejected
            if (!onrejected) { // 如果没有传递 onrejected 参数,默认实现一个,确保 catch 方法能够捕获到
              onrejected = (reason) => reason
            }
            const nextReject = self.onrejected(onrejected)
            reject(nextReject)
            break
          case 'pending':   // 
          default:
              setTimeout(waitStatus, 0) // 只要是 pending 状态,继续等待,直到不是 pending
              break
        }
      }, 0);
    })
  }

  /**
   * 捕获异常
   * @param {(reason: any) => void} onrejected
   */
  this.catch = function(onrejected) {
    const self = this
    setTimeout(function reject() {if (self.status === 'rejected') {self.onrejected(onrejected)
      } else {setTimeout(reject, 0);
      }
    }, 0);
  }

  // 直接执行
  this.executor(resolve.bind(this), reject.bind(this));
}

目前不考虑参数传入的正确性,假设传入的参数全部是正确的情况下,在 nodejs 环境下能够正常运行。以下是测试代码:


// 覆盖 nodejs 环境中默认的 Promise 对象
global.Promise = MyPromise

async function test () {const r = await new Promise((resolve) => {setTimeout(() => {resolve(121)
    }, 1000);
  })
  console.log(r)    // 打印 121
}

test()

以上代码主要是使用 setTimeout 方法去检查 Promise 对象内部的状态,一旦发生变化立即作出相应的处理。源代码在此。欢迎拍砖。

谢谢观看!

正文完
 0