首页 > 其他分享 >Promises/A+ 详解及实现

Promises/A+ 详解及实现

时间:2024-04-09 10:33:35浏览次数:28  
标签:Promises resolve 实现 onFulfilled 详解 reject 2.3 2.2 onRejected

规范:Promises/A+https://promisesaplus.com/

此篇文章将在 Node 环境通过 Class  语法来实现一个符合 Promises/A+ 规范的 MyPromise  ,通过官方 872 个测试用例

文章中 x.x.x 标记如 2.1.1 表示规范中对应的规范序号;myPromise  表示 MyPromise  的一个实例对象

【2.1】MyPromise 将有 3 个状态:

  • 【2.1.1】pending:myPromise  的状态还没发生改变,接下来可变为完成态(fulfilled)或拒绝态(rejected)
  • 【2.1.2】fulfilled:myPromise  处于成功态,该状态将不能继续发生改变,且将拥有一个不可变的值(value)
  • 【2.1.3】rejected:myPromise  处于拒绝态,该状态将不能继续发生改变,且将拥有一个不可变的拒因(reason)

初始状态为 pending

const PENDING = Symbol('PENDING')
const FULFILLED = Symbol('FULFILLED')
const REJECTED = Symbol('REJECTED')

class MyPromise {
  state = PENDING

  // value or reason
  result
}

MyPromise 构造函数接受一个函数参数 func  :

  •  func  会在 MyPromise 被初始化时立即同步执行
  •  func  会接受两个函数参数:resolve  、reject  分别用来将myPromise  的状态改变为fulfilled  和rejected
  •  func  在若在执行时抛出一个异常e  ,将会以e  来 rejectmyPromise
const PENDING = Symbol('PENDING')
const FULFILLED = Symbol('FULFILLED')
const REJECTED = Symbol('REJECTED')

class MyPromise {
  state = PENDING

  // value or reason
  result

  constructor(func) {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)

    try {
      func(this.resolve, this.reject)
    } catch(e) {
      this.reject(e)
    }
  }

  resolve() {
    // TODO 将 myPromise 的状态变为 fulfilled
  }

  reject() {
    // TODO 将 myPromise 的状态变为 rejected
  }
}

【2.2】MyPromise 将提供一个 then  方法,来访问 MyPromise 的当前或最终值(value)或拒因(reason),then  方法接收两个参数:

myPromise.then(onFulfilled, onRejected)

【2.2.1】onFulfilled  与 onRejected  都是可选项

  • 【2.2.1.1】onFulfilled  若不是一个函数,将被忽略
  • 【2.2.1.2】onRejected  若不是一个函数,将被忽略

【2.2.2】若 onFulfilled  是一个函数

  • 【2.2.2.1】当myPromise  的状态处于 fulfilled 时将被调用,且将myPromise  的 value 作为onFulfilled  的第一个参数
  • 【2.2.2.2】当myPromise  的状态没有处于 fulfilled 时将不能被调用
  • 【2.2.2.3】onFulfilled  只能被调用一次

【2.2.3】若 onRejected  是一个函数

  • 【2.2.3.1】当myPromise  的状态处于 rejected 时将被调用,且将myPromise  的 reason 作为onRejected  的第一个参数
  • 【2.2.3.2】当myPromise  的状态没有处于 rejected 时将不能被调用
  • 【2.2.3.3】onRejected  只能被调用一次

【2.2.4】onFulfilled  或 onRejected  将异步调用,应在 then  方法调用的那一轮事件循环之后的新执行栈中执行,可以采用宏任务(macro-task)机制也可采用微任务(micro-task)机制,因本篇文章是在 Node 环境中,因此采用 process.nextTick  API 将任务放置在微任务队列中执行

【2.2.5】onFulfilled  或 onRejected  将作为普通函数调用,即没有 this  指向

【2.2.6】then  可以在同一个 myPromise  上被调用多次

  • 【2.2.6.1】当myPromise  的状态变为 fulfilled,所有的onFulfilled  回调将按照他们对then  的原始调用的顺序执行
  • 【2.2.6.2】当myPromise  的状态变为 rejected,所有的onRejected  回调将按照他们对then  的原始调用的顺序执行

【2.2.7】then  将返回一个 MyPromise:

myPromise2 = myPromise1.then(onFulfilled, onRejected)
  • 【2.2.7.1】如onFulfilled  或onRejected  返回一个值x  ,则运行  [[Resolve]](myPromise2, x)  的解决过程(在代码中详解,即resolvePromise  函数)
  • 【2.2.7.2】如onFulfilled  或onRejected  抛出一个异常e  ,myPromise2  将以e  为拒因状态变为 rejected
  • 【2.2.7.3】如onFulfilled  不是一个函数且myPromise1  处于 fulfilled 状态,则myPromise2  将以与myPromise1  相同的 value 来 fulfilled
  • 【2.2.7.4】如onRejected  不是一个函数且myPromise1  处于 rejected 状态,则myPromise2  将以与myPromise1  相同的 reason 来 rejected
const PENDING = Symbol('PENDING')
const FULFILLED = Symbol('FULFILLED')
const REJECTED = Symbol('REJECTED')

function resolvePromise(myPromise2, x, resolve, reject) {
  // 2.3.1 如果 myPromise2 和 x 指向同一对象,则以一个 TypeError 为 reason 来 reject myPromise1
  if (x === myPromise2) {
    return reject(new TypeError('提供优质web前端、APP、小程序、2D/3D游戏、专业设计、UI特效解决方案,如有需求可私可访:https://ufrontend.com/'))
  }
  // 2.3.2 如果 x 是 MyPromise 实例,则使 myPromise2 采用 x 的状态,具体如下
  if (x instanceof MyPromise) {
    // 2.3.2.1 如果 x 处于 pending, myPromise2 需保持挂起,直到 x 被 fulfilled 或 rejected
    if (x.state === PENDING) {
      x.then(
        y => {
          // 将 value: y 再调用 resolvePromise
          resolvePromise(myPromise2, y, resolve, reject)
        },
        reject
      )
    } else if (x.state === FULFILLED) {
      // 2.3.2.2 当 x 状态为 fulfilled 时,以 x.result 为 value 来 resolve myPromise1
      resolve(x.result)
    } else {
      // rejected
      // 2.3.2.3 当 x 状态为 rejected, ,以 x.result 为 reason 来 reject myPromise1
      reject(x.result)
    }
  } else if (typeof x === 'function' || (x !== null && typeof x === 'object')) {
    // 2.3.3 如果是 object or function

    // 2.3.3.1 定义变量 `then`,尝试赋值为 `x.then`
    // 2.3.3.2 如果取 `x.then` 的值时抛出异常 `e` ,则以 `e` 为据因 reject myPromise1
    let then
    try {
      then = x.then
    } catch (e) {
      return reject(e)
    }
    // 2.3.3.3 如果 `then` 是一个函数,调用 `then` 并修改 this 为 `x`
    // 第一个参数为 _resolvePromise,第二个参数为 _rejectPromise
    if (typeof then === 'function') {
      let called = false

      try {
        then.call(
          x,
          // 2.3.3.3.1 如果 _resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](myPromise2, y)
          y => {
            // 2.3.3.3.3 如果 _resolvePromise 和 _rejectPromise 均被调用,
            // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            if (!called) {
              called = true
              resolvePromise(myPromise2, y, resolve, reject)
            }
          },
          // 2.3.3.3.2 如果 _rejectPromise 以值 r 为参数被调用,则以 r 为拒因 reject myPromise1
          r => {
            // 2.3.3.3.3 如果 _resolvePromise 和 _rejectPromise 均被调用,
            // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            if (!called) {
              called = true
              reject(r)
            }
          }
        )
      } catch (e) {
        // 2.3.3.3.4 如果调用 then 方法抛出了异常 e
        // 2.3.3.3.4.1 如果 _resolvePromise 或 _rejectPromise 已经被调用,则忽略之
        if (called) return
        // 2.3.3.3.4.2 否则以 `e` 为据因 reject myPromise1
        reject(e)
      }
    } else {
      // 2.3.3.4 如果 `then` 不是函数,以 x 为参数 resolve myPromise1
      resolve(x)
    }
  } else {
    // 2.3.4 如果 x 不为对象或者函数,以 x 为参数 resolve myPromise1
    resolve(x)
  }
}

class MyPromise {
  state = PENDING

  // value or reason
  result

  onFulfilledCallbacks = []
  onRejectedCallbacks = []

  constructor(func) {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)

    try {
      func(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }
  }

  resolve() {
    // TODO 将 MyPromise 的状态变为 fulfilled
  }

  reject() {
    // TODO 将 MyPromise 的状态变为 rejected
  }

  then(onFulfilled, onRejected) {
    // 2.2.7.3
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    // 2.2.7.4
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }

    const myPromise2 = new MyPromise((resolve, reject) => {
      const handleFulfilled = value => {
        try {
          const x = onFulfilled(value)
          // 2.2.7.1
          resolvePromise(myPromise2, x, resolve, reject)
        } catch (e) {
          // 2.2.7.2
          reject(e)
        }
      }

      const handleRejected = reason => {
        try {
          const x = onRejected(reason)
          // 2.2.7.1
          resolvePromise(myPromise2, x, resolve, reject)
        } catch (err) {
          // 2.2.7.2
          reject(err)
        }
      }

      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(handleFulfilled)
        this.onRejectedCallbacks.push(handleRejected)
      } else if (this.state === FULFILLED) {
        // 2.2.4
        process.nextTick(() => {
          handleFulfilled(this.result)
        })
      } else {
        // rejected

        // 2.2.4
        process.nextTick(() => {
          handleRejected(this.result)
        })
      }
    })

    // 2.2.7
    return myPromise2
  }
}

最终实现 resolve  及 reject  方法

class MyPromise {
  // ...
  resolve(value) {
    if (this.state === PENDING) {
      // 2.2.4
      process.nextTick(() => {
        this.result = value
        this.state = FULFILLED
        this.onFulfilledCallbacks.splice(0).forEach(cb => cb(value))
      })
    }
  }

  reject(reason) {
    if (this.state === PENDING) {
      // 2.2.4
      process.nextTick(() => {
        this.result = reason
        this.state = REJECTED
        this.onRejectedCallbacks.splice(0).forEach(cb => cb(reason))
      })
    }
  }
  // ...
}

标签:Promises,resolve,实现,onFulfilled,详解,reject,2.3,2.2,onRejected
From: https://blog.csdn.net/ufrontend/article/details/137541153

相关文章

  • 开源模型应用落地-qwen1.5-7b-chat与sglang实现推理加速的正确姿势(二)
    一、前言  经过开源模型应用落地-qwen1.5-7b-chat与sglang实现推理加速的正确姿势(一)的实践,相信大家已经成功地运行起一个性能良好的sglangAPI服务。现在,在充裕的服务器资源配置下,接下来可以继续进行一些优化工作。二、术语2.1.sglang  SGLangisastructuredge......
  • Set集合以及其中实现类的底层原理分析
    Set集合的特点无序:存取顺序不一致如存入张三、李四、王五。而遍历获取到的是李四,张三,王五不重复:可以去除重复无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素set集合的实现类HashSet:无序、不重复、无索引LinkedHashSet:有序、不重复、无索......
  • Kubernetes统一管理vGPU:原理、实现与挑战
    目录一、vGPU原理与需求二、Kubernetes统一管理vGPU的实现三、面临的挑战与解决方案四、拟解决方案五、总结导言:随着云计算和虚拟化技术的快速发展,GPU资源的共享和统一管理成为了云计算领域的一个重要课题。Kubernetes,作为容器编排领域的领头羊,其对于GPU资源的管理能......
  • python计算机毕设【附源码】基于html的校园网设计与实现(django+mysql+论文)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在信息技术快速发展的今天,互联网已经成为人们获取信息、交流沟通的重要平台。对于学校而言,拥有一个功能齐全、操作简便的校园网系统显得尤为重要。基于HTML......
  • VOL框架 其他页面调用GetPageData的实现方法
    VOL框架其他页面调用GetPageData的实现方法例如:B页面访问A页面的GetPageData实现思路:1、A后端新建一个Controller,通过这个Controller调用A的service的GetPageData   注意 HttpPost参数要加上 [FromBody][HttpPost,Route("getSubList"),AllowAnonymous]......
  • C++与Qt中回调函数的两种实现方法
    一.回调函数介绍1.概念回调函数是一种在程序运行期间通过函数指针调用的函数,它通常用于实现事件驱动、异步通信、消息传递等功能。在回调函数中,被调用的函数通常称为回调函数(CallbackFunction),而调用回调函数的函数通常称为回调函数容器(CallbackContainer)。回调函数容器可......
  • 如何通过跨网软件,实现网络隔离后的文件安全收发摆渡?
    随着企业数字化转型的逐步深入,企业投入了大量资源进行信息系统建设,信息化程度日益提升。绝大多数企业为了防止内部核心数据泄露,会实施网络隔离,比如内外网隔离,或者在内部网络中又划分出研发网、办公网、生产网等。在专业化分工协作的今天,企业与外部客户、合作伙伴等需进行频繁的数......
  • 深入理解PHP+Redis实现布隆过滤器(亿级大数据处理和黑客攻防必备)
    布隆过滤器极简概括英文名称BloomFilter,用于判断一个元素是否在一个大数据集合中,如果检测到存在则有可能存在,如果不存在则一定不存在。Redis官网对于布隆过滤器的说明:https://redis.io/docs/data-types/probabilistic/bloom-filter/使用场景防止缓存穿透:用于快速判断某个商......
  • 卷积神经网络python实现的三种方法
    1、介绍TensorFlow、PyTorch和Keras都是流行的深度学习框架,它们都具有成熟的卷积神经网络(CNN)实现。选择哪种框架取决于您的偏好、项目需求以及团队的技术栈。2、特点TensorFlow:TensorFlow是由Google开发的开源深度学习框架,广泛用于生产环境和研究领域。TensorFlow具有丰富的......
  • 预处理详解
    要想了解预处理,首先要了解预定义符号,它是由__和大写字母组成的:了解完预定义符号,就要知道用什么来表示预定义符号,用#define来定义常量和宏,#define定义常量:它的表达式为:#definenamestuff。它的基本代码为:#include<stdio.h>//#define定义常量#defineMAX1000intmain(......