手写一个符合Promise A+规范的Promise

80 阅读6分钟
原文链接: mp.weixin.qq.com

关注  前端技术专栏 ,回复“  资源 ”免费领取全套视频教程 前言 记得之前发过一篇关于Promise文章的讲解,不过都不是很深入,只是对使用上的理解,所以这次我将会带着各位通过JavaScript来实现一个Promise,并且是符合规范的,最后可以通过promises-aplus-tests来进行跑测。 整个实现主要通过Promise A+规范来做的,可以参考以下地址:

https://promisesaplus.com/

正文 接下来的内容我将直接贴出源码,因为我在写的时候都以逐行加了注释来说明代码理解,所以就不会再来逐行解读了,如各位从其中发现任何问题欢迎留言指正

utils.js 文件
const {  PENDING,  FULFILLED,  REJECTED,  getType,  isArray,  isObject,  isFunction} = {  PENDING: 'pending',  FULFILLED: 'fulfilled',  REJECTED: 'rejected',  getType: (t) => (v) => Object.prototype.toString.call(v) === `[object ${t}]`,  isArray: (v) => getType('Array')(v),  isObject: (v) => getType('Object')(v),  isFunction: (v) => getType('Function')(v),}// 解析promise,这里将会处理返回的promise或者其它情况下promise的状态让其直接变为完成状态并将参数值传入到下一个thenconst resolvePromise = (promise2, x, resolve, reject) => {  let caller = false // 定义一个开关,为了让promise的状态一旦确定则不能再做修改  // 如果promise是它自己,避免自己等待自己,直接抛错  if (promise2 === x) {    return reject(      new TypeError('Chaining cycle detected for promise #<Promise>')    )  }  // 如果x是对象或者是一个函数的时候 那么它可能是一个promise,接下来将进一步解析。 这里是为了兼容第三方promise库,例如:q es6-promise  if ((x && isObject(x)) || isFunction(x)) {    try {      const then = x.then      // 确定then是一个函数的时候,那么肯定是一个promise      if (isFunction(then)) {        // 执行then函数        then.call(          x,          y => {            if (caller) return null            caller = true            // 递归解析,直到不是一个promise            resolvePromise(promise2, y, resolve, reject)          },          e => {            if (caller) return null            caller = true            // 如果发生错误,将直接变为拒绝状态并返回错误信息            reject(e)          }        )      } else {        // 如果不是一个promise,则直接将其状态变为完成并返回其值        resolve(x)      }    } catch (err) {      if (caller) return null      caller = true      // 发生错误这里直接将状态变为拒绝并返回错误信息      reject(err)    }  } else {    // 当x是一个普通值,那么将直接变为完成状态,并返回其值    resolve(x)  }}// 专门用来处理then的onFulfilled Or onRejected 回调const onFulfilledOrOnRejectedHandler = (  promise2,  onFulfilledOrOnRejectedCallBack,  resolve,  reject,  value) => {  // 此处的定时器为了等待Promise的实例完成  setTimeout(() => {    try {      // 执行then的resolve or reject函数并传入其值,通过一个变量x去拿到当前resolve执行后的返回值      const x = onFulfilledOrOnRejectedCallBack(value)      // 解析then的resolve or reject执行,如果返回一个promise或者其它值情况的处理      resolvePromise(promise2, x, resolve, reject)    } catch (err) {      // 如果返回发生错误,则直接reject      reject(err)    }  }, 0)}module.exports = {  PENDING,  FULFILLED,  REJECTED,  isArray,  isObject,  isFunction,  onFulfilledOrOnRejectedHandler}
主文件 promise.js
const {  PENDING,  FULFILLED,  REJECTED,  isArray,  isObject,  isFunction,  onFulfilledOrOnRejectedHandler} = require('./utils')class Promise {  constructor(executor) {    this.status = PENDING    this.doneValue = undefined // 同步executor执行后,保存resolve函数参数值    this.resason = undefined // 同步executor执行后,保存reject函数的参数值    // 发布订阅模式。then方法执行时如发现状态未变,则订阅then方法执行的 完成 Or 拒绝 回调    this.doneCallbacks = []    this.failCallbacks = []    const resolve = (doneValue) => {      // 如果值是一个promise      if (doneValue instanceof Promise) {        // 将递归解析resolve中的参数直到不是一个promise对象        return doneValue.then(resolve, reject)      }      // 判断只有是等待状态的时候才进行成功处理,为了一旦状态发生改变将不会再改变状态      if (this.status === PENDING) {        this.status = FULFILLED        this.doneValue = doneValue        // 执行then方法的resolve订阅回调        this.doneCallbacks.forEach((fn) => fn())      }    }    const reject = (resason) => {      // 判断只有是等待状态的时候才进行拒绝处理,为了一旦状态发生改变将不会再改变状态      if (this.status === PENDING) {        this.status = REJECTED        this.resason = resason        // 执行then方法的reject订阅回调        this.failCallbacks.forEach((fn) => fn())      }    }    // 异常处理,一旦发生错误直接将状态变为拒绝并返回错误信息    try {      // 同步执行 executor promise的回调      executor(resolve, reject)    } catch (e) {      reject(e)    }  }  // 内部定时器的作用是为了等待Promise的实例完成再执行  then(onFulfilled, onRejected) {    // 如果 onFulfilled Or onRejected 不是函数,则将其忽略,默认赋值一个函数返回其值,为了让值往下穿透    onFulfilled = isFunction(onFulfilled) ? onFulfilled : v => v    onRejected = isFunction(onRejected) ? onRejected : (err) => { throw err }    // then的执行必须返回一个新的promise,形成无限链式调用(也就是形成递归)    const promise2 = new Promise((resolve, reject) => {      let value = ''      let onFulfilledOrOnRejectedCallBack = ''      // 如果状态已变成完成状态 则保存onFulfilled回调 并保存完成的donevalue      if (this.status === FULFILLED) {        onFulfilledOrOnRejectedCallBack = onFulfilled        value = this.doneValue      }      // 如果状态已变成完成状态 则保存onRejected回调 并保存拒绝的resason      if (this.status === REJECTED) {        onFulfilledOrOnRejectedCallBack = onRejected        value = this.resason      }      // 执行对应状态的 onFulfilled Or onRejected 并传入对应的value      if (isFunction(onFulfilledOrOnRejectedCallBack)) {        setTimeout(() => {          onFulfilledOrOnRejectedHandler(            promise2,            onFulfilledOrOnRejectedCallBack,            resolve,            reject,            value          )        }, 0)      }      // 如果状态不变      if (this.status === PENDING) {        // 订阅then的完成回调        this.doneCallbacks.push(() => {          setTimeout(() => {            onFulfilledOrOnRejectedHandler(              promise2,              onFulfilled,              resolve,              reject,              this.doneValue            )          }, 0)        })        // 订阅then的拒绝回调        this.failCallbacks.push(() => {          setTimeout(() => {            onFulfilledOrOnRejectedHandler(              promise2,              onRejected,              resolve,              reject,              this.resason            )          }, 0)        })      }    })    return promise2  }  // catch的回调利用then方法的实现  catch(failCallback) {    return this.then(null, failCallback)  }  // finally 是无论如何都会执行的  // 如果返回一个promise,那么将会等待这个promise执行完毕  finally(callback) {    return this.then(      x => Promise.resolve(callback()).then(() => x),      e =>        Promise.reject(callback()).then(() => {          throw e        })    )  }  // resolve 的静态方法  static resolve(v) {    return new Promise((resolve) => {      resolve(v)    })  }  // reject 的静态方法  static reject(err) {    return new Promise((resolve, reject) => {      reject(err)    })  }  static all(promises) {    // 看一下进来的参数是不是一个数组    promises = isArray(promises) ? promises : []    let fulfilledCount = 0 // 状态变完成的个数    let promisesLength = promises.length // 需要完成的个数    let results = new Array(promisesLength) // 设置结果数组长度    return new Promise((resolve, reject) => {      // 如果是个空数组,那么将直接变为完成状态,并传入空数组参数值      if (promisesLength === 0) return resolve([])      // 遍历数组中的promise      promises.forEach((promise, index) => {        // 判断是不是一个promise        if (isObject(promise) && isFunction(promise.then)) {          promise.then(            (value) => {              // 向结果数组中存入 对应返回数据值              results[index] = value              // 当等于了需完成的个数,说明已全部都处理完了,那么就直接将状态变为完成,返回最终数据              if (++fulfilledCount === promisesLength) resolve(results)            },            (err) => reject(err) // 只要一个发生错误,那么直接变为失败,并返回失败原因          )        } else {          // 如果不是一个promise,将直接存值          results[index] = promise          if (++fulfilledCount === promisesLength) resolve(results)        }      })    })  }  // 看谁快  static race(promises) {    promises = isArray(promises) ? promises.filter(item => isObject(item) && isFunction(item.then)) : []    return new Promise((resolve, reject) => {      promises.forEach((promise) => {        promise.then(          (value) => resolve(value),          (err) => reject(err)        )      })    })  }}// 延迟执行,这个主要用于promise A+规范跑测使用Promise.defer = Promise.deferred = () => {  let dfd = {}  dfd.promise = new Promise((resolve, reject) => {    dfd.resolve = resolve    dfd.reject = reject  })  return dfd}module.exports = Promise
结语

以上就是全部的代码了,代码不是很多,Promise A+规范主要在于then方法,其它辅助方法都比较容易实现。

下面是这个源码的仓库地址,如果想直接测试一下可以拉下来跑一跑

https://github.com/wujiabk/promise

猜你爱看 一文搞懂Linux CentOS7中关于MongoDB的认证和授权设置 只需5分钟,让你了解未来可能推翻Node的新轮子 Deno 1.0 Vue 3.0 初体验《从构建项目到实现一个todoList》

微  博:前端吴佳

QQ群:856363266


长按识别二维码

关注「前端技术专栏」 加星标

每天给您推送最新原创技术文章

好看,帮点击在看 ❤️