Promises/A+

这是一个开放标准,旨在让不同开发者实现的 JavaScript Promise 能够无缝衔接并应用——由前辈们制定,为其他后来者提供参考

一个 promise 所表示的是异步操作的结果。与 promise 交互的主要方式是通过它的 then 方法,该方法会注册所传入的回调函数,回调函数将接收 promise 的最终值或者 promise 无法被满足时的原因。

本规范详细说明了 then 方法的行为,为所有符合 Promises/A+ 标准的 promise 实现提供可靠的基础。因此本规范的更新或修订应被视为非常稳定。虽然 Promises/A+ 组织可能会偶尔对本规范进行向后兼容的小幅度修订,以解决新发现的边缘情况,但我们依然会在经过认真仔细的考虑、讨论和测试后,才会去整合重大或者不向后兼容的变更。

在过去,Promises/A+ 不仅明确早期 Promise/A 提案中的涉及的行为条款,而且还扩展了一些涵盖实际行为的内容,并且省略了那些不清不楚或存在问题的部分。

最后要说的是,Promises/A+ 规范的核心并不涉及如何创建、满足或拒绝 promise,而是选择专注于提供一个强大的 then 方法以确保不同实现之间的兼容性。大概未来的相关规范才可能会涉及如何创建、满足和拒绝 promise 这些主题吧。

1 专业术语

  1. thenable: 一个具有 then 方法的对象或函数。
  2. promise:一个具有 then 方法的对象或函数,then 方法的行为符合本规范。
  3. value:是一个合法的 JS 值,含 undefinednullthenablepromise 等。
  4. exception:通过 throw 语句抛出的值。
  5. reason:通常用于表示 promise 被拒绝/无法实现的原因,也是个值。

2 详细规范

2.1 Promise 状态

一个 promise 必须处于以下三种状态之一:

待定中(pending)已实现(fulfilled)已拒绝(rejected)

关于这些状态的描述如下:

  1. 待定中 —— pending:

    1. 可以转变为其它两种状态,也就是已实现(fulfilled)或已拒绝(rejected)
  2. 已实现 —— fulfilled:
    1. 禁止从该状态转变为其它状态,状态不可改变
    2. 必须有一个不可改变的值(value —— 完成后的成果!!)
  3. 已拒绝 —— rejected:
    1. 禁止从该状态转变为其它状态,状态不可改变
    2. 必须有一个不可改变的原因(reason —— 为什么拒绝!?)

注意:不可改变并不意味着深层次的不可变(比如属性描述符中 writeable: false),你可以通过对当前状态进行全等判断(===),从而更改相应的值/原因和状态后,那么不可改变自然而然的就会成立了。

2.2 then 方法

一个 promise 必须提供一个 then 方法,它可以访问当前或最终的值或者原因。

promisethen 方法接受两个参数:

promise.then(onFulfilled, onRejected)
  1. onFulfilledonRejected 均是可选参数:

    1. 如果 onFulfilled 不是一个函数,则必须被忽略。
    2. 如果 onRejected 不是一个函数,则必须被忽略。

    被忽略是指我们不对它做任何的处理,不会抛出任何的错误

  2. 如果 onFulfilled 是一个函数:

    1. 必须在 promise 被实现后调用,且以 promise 的值(value)作为第一个参数。
    2. promise 被实现之前不可调用。
    3. 不允许被多次调用。
  3. 如果 onRejected 是一个函数:

    1. 必须在 promise 被拒绝后调用,且以 promise 的原因(reason)作为第一个参数。
    2. promise 被拒绝之前不可调用。
    3. 不允许被多次调用。
  4. onFulfilledonRejected 必须在执行上下文栈仅包含平台代码时才被调用。[[3.1](#3 引注)]

  5. onFulfilledonRejected 必须作为函数调用(没有 this 值)。[[3.2](#3 引注)]

  6. then 可以在同一个 promise 上被多次调用。

    1. promise 被实现时,所有相应的 onFulfilled 回调必须按它们调用 then 的顺序执行。
    2. promise 被拒绝时,所有相应的 onRejected 回调必须按它们调用 then 的顺序执行。
  7. then 必须返回一个 promise [[3.3](#3 引注)]。

    promise2 = promise1.then(onFulfilled, onRejected);
    1. 如果 onFulfilledonRejected 返回一个值 x,则运行 Promise 解决过程 [[Resolve]](promise2, x)[[2.3](#2.3 Promise 解决过程)]。
    2. 如果 onFulfilledonRejected 抛出异常 e,则 promise2 必须以 e 作为原因被拒绝。
    3. 如果 promise1 被实现且 onFulfilled 不是一个函数,那么 promise2 必须以与 promise1 相同的值(value)被实现。
    4. 如果 promise1 被拒绝且 onRejected 不是一个函数,那么 promise2 必须以与 promise1 相同的原因(reason)被拒绝。

2.3 Promise 解决过程

Promise 解决过程 是一种抽象操作,它接受一个 promise 和一个值作为输入,表示为 [[Resolve]](promise, x)。如果 x 是一个 thenable,则会尝试使 promise 采用 x 的状态,前提是 x 至少在某种程度上表现得像一个 promise。否则,它将用值 x 来实现 promise

thenable 的这种处理方式使得不同的 promise 实现能够有效兼容,只要它们提供符合 Promises/A+ 标准的 then 方法。但是也允许 Promises/A+ 实现能够“接纳”那些具有合理 then 方法的非标准实现。

要实现 [[Resolve]](promise, x),请按照以下步骤操作:

  1. 如果 promisex 指向同一个对象,则以 TypeError 拒绝 promise 作为原因。
  2. 如果 x 是一个 promise,则采用其状态 [[3.4](#3 引注)]:
    1. 如果 x 是待定状态,promise 必须保持待定,直到 x 被实现或拒绝。
    2. 如果 x 被实现,使用相同的值实现 promise
    3. 如果 x 被拒绝,使用相同的原因拒绝 promise
  3. 否则,如果 x 是一个对象或函数:
    1. then 设置为 x.then。[[3.5](#3 引注)]
    2. 如果检索属性 x.then 时抛出异常 e,则以 e 作为原因拒绝 promise
    3. 如果 then 是一个函数,则以 x 作为 this 调用它,第一个参数为 resolvePromise,第二个参数为 rejectPromise,其中:
      1. 如果 resolvePromise 被调用并传入值 y,则运行 [[Resolve]](promise, y)
      2. 如果 rejectPromise 被调用并传入原因 r,则以 r 拒绝 promise
      3. 如果同时调用了 resolvePromiserejectPromise,或对同一参数进行了多次调用,第一次调用优先,后续调用将被忽略。
      4. 如果调用 then 时抛出异常 e
        1. 如果 resolvePromiserejectPromise 已被调用,则忽略该异常。
        2. 否则,以 e 作为原因拒绝 promise
    4. 如果 then 不是一个函数,则用 x 来实现 promise
  4. 如果 x 既不是对象也不是函数,则用 x 来实现 promise

如果一个 promise 被一个循环的 thenable 链中的对象解决,而 [[Resolve]](promise, thenable) 的递归性质使得它被再次调用,按照上述算法将会导致无限递归。虽然算法并不强制要求检测这种递归,但我们鼓励实现者可以这样做。如果检测到存在循环,则应以一个语义清晰的 TypeError 拒绝 promise。[[3.6](#3 引注)]

3 引注

  1. 这里的“平台代码”指的是引擎、环境和 promise 的实现代码。实际上,这一要求确保 onFulfilledonRejected 在调用 then 的事件循环转之后异步执行,并且在一个新的调用栈中。这可以通过“宏任务”机制(如 setTimeoutsetImmediate)或“微任务”机制(如 MutationObserverprocess.nextTick)来实现。由于 promise 实现被视为平台代码,它本身可能包含一个任务调度队列或“跳板”,用于调用处理程序。

  2. 也就是说,在严格模式下,this 的值将是 undefined;在非严格模式下,this 将指向全局对象。

  3. 实现可以允许 promise2 === promise1,前提是该实现满足所有要求。每个实现应记录是否可以产生 promise2 === promise1 以及在什么条件下可以实现。

  4. 通常,只有当 x 来自当前实现时,才能确定 x 是一个真正的 promise。这一条款允许使用特定于实现的方法来采用已知符合标准的 promises 的状态。

  5. 这个过程首先存储对 x.then 的引用,然后测试该引用,最后调用该引用,避免了对 x.then 属性的多次访问。这种预防措施对于确保在访问器属性的情况下保持一致性非常重要,因为该属性的值可能在多次检索之间发生变化。

  6. 实现不应对 thenable 链的深度设置任意限制,并假设超出该限制的递归将是无限的。只有真正的循环才应导致 TypeError;如果遇到无限的不同 thenable 链,则无限递归是正确的行为。

Promise/A+ 规范 - 中文版本的更多相关文章

  1. Promise A+ 规范【中文版】

    0. 前言 本文为Promise A+规范的中文译文,Promise A+规范英文版原文链接:Promise A+. 正文如下: 一个开放.健全且通用的 JavaScript Promise 标准.由 ...

  2. 按照 Promise/A+ 规范逐行注释并实现 Promise

    0. 前言 面试官:「你写个 Promise 吧.」 我:「对不起,打扰了,再见!」 现在前端越来越卷,不会手写 Promise 都不好意思面试了(手动狗头.jpg).虽然没多少人会在业务中用自己实现 ...

  3. Angularjs中文版本开发指南发布

    从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs ...

  4. Promise A 规范的一个简单的浏览器端实现

    简单的实现了一个promise 的规范,留着接下来模块使用.感觉还有很多能优化的地方,有时间看看源码,或者其他大神的代码 主要是Then 函数.回调有点绕人. !(function(win) { fu ...

  5. 【javascript】Promise/A+ 规范简单实现 异步流程控制思想

    ——基于es6:Promise/A+ 规范简单实现 异步流程控制思想  前言: nodejs强大的异步处理能力使得它在服务器端大放异彩,基于它的应用不断的增加,但是异步随之带来的嵌套.难以理解的代码让 ...

  6. Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)

    1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...

  7. 如何在FreePBX ISO 中文版本安装讯时网关,潮流16FXS 网关和潮流话机

    如何在FreePBX ISO 中文版本安装讯时网关,潮流16FXS 网关和潮流话机摘自:http://www.siplab.cn/?p=664 1)迅时的fxo口网关要注册到asterisk,所以现在 ...

  8. 手写一款符合Promise/A+规范的Promise

    手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看.如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的.主要 ...

  9. when 让你跳出异步回调噩梦 node.js下promise/A规范的使用

    其实关于promise 的博客,前端时间专门写了一篇关于 promise 规范的文章,promise规范 让 javascript 中的异步调用更加人性化. 简单回忆下: promise/A规范定义的 ...

  10. Promise/A+规范

    1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...

随机推荐

  1. C# webapi 跨域

    #region 启用跨域访问 app.UseCors(builder => builder .AllowAnyMethod() .SetIsOriginAllowed(_ => true) ...

  2. OKR 目标和关键成果

    OKR(Objectives and Key Results)是目标与关键成果管理法,是一套明确和跟踪目标及其完成情况的管理工具和方法.1.OKR首先是沟通工具:团队中的每个人都要写OKR,所有这些O ...

  3. Machine Learning Week_1 Introduction 5-8

    目录 1.5 Vedio: Supervised Learning unfamiliar words 1.6 Reading: Supervised Learning unfamiliar words ...

  4. 全中国有多少公网IP地址?

    之前为了准备CTF比赛,搞了一个云服务器,顺便申请了一个公网IP. 看着申请到的IP地址,我突然想到了一个问题:不是早就说IP地址已经耗尽了吗,为什么我随便就能申请到,是谁在负责IP地址的管理分配,咱 ...

  5. 3.16 Linux删除文件或目录(rm命令)

    当 Linux 系统使用很长时间之后,可能会有一些已经没用的文件(即垃圾),这些文件不但会消耗宝贵的硬盘资源,还是降低系统的运行效率,因此需要及时地清理. rm 是强大的删除命令,它可以永久性地删除文 ...

  6. 接口自动化AES对称加密为什么密钥key是16位的?

    对称加密AES,加密和解密的密钥是同一个 AES是一个分组加密算法,AES有三种密钥长度(128.192.256)比特,常用的是128比特,也就是16位 AES常用的加密模式有:ECB,ECB是将明文 ...

  7. P9150 邮箱题

    P9150 邮箱题 Alex_Wei 做法妙. 思路 首先我们可以建出两张图,一张是按照题目的要求形成的有向图,一张是由有向边 \((i,k_i)\) 形成的钥匙图. 在钥匙图中,每个点有且仅有一入度 ...

  8. Impala源代码分析(3)-backend查询执行过程

    4 Replies 这篇文章主要介绍impala-backend是怎么执行一个SQL Query的. 在Impala中SQL Query的入口函数是: void ImpalaServer::query ...

  9. 用文字“画出”状态图:用 AI+Mermaid.js 解决对象状态变化的处理问题

    什么是状态图 状态图用于描述对象在其生命周期内的状态变化及其处理,例如业务办理流程.病情处置等. 什么是Mermaid Mermaid.js是一个开源项目,它允许你通过简单的语法来绘制图表. 无论你是 ...

  10. NOIP2024加赛8

    NOIP2024加赛8 T1 flandre 第 4 个样例没给全,说明这可以直接猜结论 首先我们假设选定了 $ x $ 个数,那么我们肯定是把他们从小到大排好序依次放,这样才能使整体效果最大.然后我 ...