手写Promise

这篇文章展示了如何从头实现一个基本的Promise类,包括构造函数、状态管理(pending,fulfilled,rejected)、then、catch、finally方法以及静态方法如all、race和静态方法的实现。示例代码中还包含了Promise的实例用法。
/*
 * File Created: Tuesday, 14th March 2023 3:39:42 pm
 * Author: hotsuitor (hotsuitor@qq.com)
 * -----
 * Last Modified: Tuesday, 14th March 2023 4:35:43 pm
 * Modified By: hotsuitor (hotsuitor@qq.com>)
 * -----
 * Copyright 2022 - 2023 Your Company, Your Company
 */

const PROMISE_STATUS_PENDING = 'pending' // 等待状态
const PROMISE_STATUS_FULFILED = 'fulfilled' // 成功状态
const PROMISE_STATUS_REJECTED = 'rejected' // 失败状态

// help function
function execFunctionWithCatchError(execFn, value, resolve, reject) {
  try {
    const result = execFn(value)
    resolve(result)
  } catch (error) {
    reject(error)
  }
}
class MyPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING // promise状态
    this.value = undefined // resolve返回值
    this.reason = undefined // reject返回值
    this.onFulFilledFns = [] // 保存成功回调
    this.onRejectedFns = [] // 保存失败回调

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILED
          this.value = value
          this.onFulFilledFns.forEach((fn) => {
            fn(this.value)
          })
        })
      }
    }

    const reject = (reason) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          this.onRejectedFns.forEach((fn) => {
            fn(this.reason)
          })
        })
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = onFulfilled || ((value) => value)
    onRejected =
      onRejected ||
      ((err) => {
        throw err
      })

    return new MyPromise((resolve, reject) => {
      // 1. when operate then,  status has confirmed
      if (this.status === PROMISE_STATUS_FULFILED && onFulfilled) {
        execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
      }
      if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
        execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
      }

      if (this.status === PROMISE_STATUS_PENDING) {
        if (onFulfilled) {
          this.onFulFilledFns.push(() => {
            execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
          })
        }
        if (onRejected) {
          this.onRejectedFns.push(() => {
            execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
          })
        }
      }
    })
  }

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

  finally(onFinally) {
    this.then(
      () => {
        onFinally()
      },
      () => {
        onFinally()
      }
    )
  }

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

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

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const values = []
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            values.push(res)
            if (values.length === promises.length) {
              resolve(values)
            }
          },
          (err) => reject(err)
        )
      })
    })
  }

  static allSettled(promises) {
    return new MyPromise((resolve) => {
      const results = []
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            results.push({ status: PROMISE_STATUS_FULFILED, value: res })
            if (results.length === promises.length) {
              resolve(results)
            }
          },
          (err) => {
            results.push({ status: PROMISE_STATUS_REJECTED, value: err })
            if (results.length === results.length) {
              resolve(results)
            }
          }
        )
      })
    })
  }
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(resolve, reject)
      })
    })
  }

  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const reasons = []
      promises.forEach((promise) => {
        promise.then(resolve, (err) => {
          reasons.push(err)
          if (reasons.length === promises.length) {
            reject(reasons)
          }
        })
      })
    })
  }
}

/** test */
const p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    console.log('--- 1 ---')
    resolve(111)
  })
}).then((res) => {
  console.log('p1 res :>> ', res)
})

const p2 = new MyPromise((resolve, reject) => {
  console.log('--- 2 ---')
  resolve(222)
})

const p3 = new MyPromise((resolve, reject) => {
  console.log('--- 3 ---')
  resolve(333)
})

const p4 = new MyPromise((resolve, reject) => {
  console.log('--- 4 ---')
  reject(444)
})

MyPromise.all([p2, p3]).then((res) => {
  console.log('p2&p3 res :>> ', res)
})

MyPromise.all([p2, p4])
  .then((res) => {
    console.log('p2&p4 res :>> ', res)
  })
  .catch((err) => {
    console.log('err :>> ', err)
  })

当然可以!以下是一个简单的手写Promise的示例: ```javascript class Promise { constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onResolveCallbacks = []; this.onRejectCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onResolveCallbacks.forEach(callback => callback()); } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectCallbacks.forEach(callback => callback()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { const fulfilledHandler = typeof onFulfilled === 'function' ? onFulfilled : value => value; const rejectedHandler = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }; const promise2 = new Promise((resolve, reject) => { const fulfillHandlerWrapper = () => { setTimeout(() => { try { const result = fulfilledHandler(this.value); resolvePromise(promise2, result, resolve, reject); } catch (error) { reject(error); } }, 0); }; const rejectHandlerWrapper = () => { setTimeout(() => { try { const result = rejectedHandler(this.reason); resolvePromise(promise2, result, resolve, reject); } catch (error) { reject(error); } }, 0); }; if (this.state === 'fulfilled') { fulfillHandlerWrapper(); } else if (this.state === 'rejected') { rejectHandlerWrapper(); } else { this.onResolveCallbacks.push(fulfillHandlerWrapper); this.onRejectCallbacks.push(rejectHandlerWrapper); } }); return promise2; } catch(onRejected) { return this.then(null, onRejected); } } function resolvePromise(promise, result, resolve, reject) { if (promise === result) { return reject(new TypeError('Chaining cycle detected for promise')); } let thenCalledOrThrow = false; if (result instanceof Promise) { result.then( value => resolvePromise(promise, value, resolve, reject), reason => reject(reason) ); } else if (result !== null && (typeof result === 'object' || typeof result === 'function')) { try { const then = result.then; if (typeof then === 'function') { then.call( result, value => { if (thenCalledOrThrow) return; thenCalledOrThrow = true; resolvePromise(promise, value, resolve, reject); }, reason => { if (thenCalledOrThrow) return; thenCalledOrThrow = true; reject(reason); } ); } else { resolve(result); } } catch (error) { if (thenCalledOrThrow) return; thenCalledOrThrow = true; reject(error); } } else { resolve(result); } } ``` 这只是一个基本的实现,还有很多细节和功能可以改进。希望对你有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值