手写实现 Promise/A+ 标准

发布于 2023-05-12 08:54:54 字数 5033 浏览 58 评论 0

本文仅作为个人记录,文中可能存在不严谨的地方。

Promise/A+ 的标准有哪些?

  • 只有一个 then 方法,没有 catchraceall 等方法。
  • then 返回一个新的 Promise。
  • 不同的 Promise 的实现需要相互调用。
  • Promise 的状态有 pendingfullfilledrejected 三种。初始状态是 pending,可以由 pending 转化为 fullfilled 或者 rejected。一旦状态确定之后,不能再被改变。
  • 更具体的官方标准,看这里

具体代码实现

function MyPromise(executor) {
  const _this = this
  // 状态
  _this.status = 'pending'
  // resolve 值
  _this.value = null
  // reject 原因
  _this.reason = null
  // resolve、reject 函数
  _this.onFullfilled = []
  _this.onRejected = []

  function resolve(value) {
    if (value instanceof MyPromise) {
      return value.then(resolve, reject)
    }

    // 其实这里采用 setTimeout 方式实现异步执行 onFullfilled/onRejected 不太符合 Event Loop 机制。下面 reject 同理。
    setTimeout(() => {
      // 只有状态为 pending 才能被改变
      if (_this.status == 'pending') {
        _this.value = value
        _this.status = 'resolved'
        _this.onFullfilled.forEach(currentValue => currentValue(value))
      }
    }, 0)
  }

  function reject(reason) {
    setTimeout(() => {
      // 只有状态为 pending 才能被改变
      if (_this.status == 'pending') {
        _this.reason = reason
        _this.status = 'rejected'
        _this.onRejected.forEach(currentValue => currentValue(reason))
      }
    }, 0)
  }

  // 注意:若执行过程出现异常,则捕获异常并执行 reject 函数。
  try {
    executor(resolve, reject)
  } catch (e) {
    reject(e)
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  let then
  let thenCallorThrow = false

  if (promise2 === x) {
    return reject(new TypeError('same Promise!'))
  }

  if (x instanceof MyPromise) {
    if (x.status === 'pending') {
      x.then(value => {
        resolvePromise(promise2, value, resolve, reject)
      }, reject)
    } else {
      x.then(resolve, reject)
    }
    return
  }

  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      then = x.then
      if (typeof then === 'function') {
        then.call(
          x,
          res => {
            if (thenCallorThrow) return
            thenCallorThrow = true
            return resolvePromise(promise2, res, resolve, reject)
          },
          err => {
            if (thenCallorThrow) return
            thenCallorThrow = true
            return reject(err)
          }
        )
      } else {
        resolve(x)
      }
    } catch (e) {
      if (thenCallorThrow) return
      thenCallorThrow = true
      return reject(e)
    }
  } else {
    return resolve(x)
  }
}

MyPromise.prototype.then = function (onFullfilled, onRejected) {
  const _this = this
  let promise2 // promise.then() 返回一个 promise 对象

  // Promise 值的穿透处理:
  // 场景如: new Promise(resolve => resolve('abc')).then().catch().then(res => {console.log('print abc')})
  onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : val => val
  onRejected =
    typeof onRejected === 'function'
      ? onRejected
      : err => {
          throw err
        }

  switch (_this.status) {
    case 'pending':
      promise2 = new MyPromise((resolve, reject) => {
        _this.onFullfilled.push(value => {
          try {
            const x = onFullfilled(value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
        _this.onRejected.push(reason => {
          try {
            const x = onRejected(reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
      break
    case 'resolved':
      promise2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            const x = onFullfilled(_this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
      break
    case 'rejected':
      promise2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            const x = onRejected(_this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
      break
    default:
      break
  }

  return promise2
}

// Promise 标准里面没有 catch、race、all 等方法,只有一个 then 方法
MyPromise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected)
}

new MyPromise((resolve, reject) => {
  resolve('right')
}).then(
  res => {
    console.log(res)
  },
  err => {
    console.warn(err)
  }
)

要了解更多可以看下这两篇文章:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

怼怹恏

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

亽野灬性zι浪

文章 0 评论 0

少年亿悲伤

文章 0 评论 0

南七夏

文章 0 评论 0

qq_EJoXxu

文章 0 评论 0

17780639550

文章 0 评论 0

萌逼全场

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文