Promises/A+规范

翻译前言:搜索已经有多篇Promises/A+规范的中文翻译,可参见[4],[5]。但[4][5]翻译都难以理解,例如[4]中未保留原规范的章节编号,不容易对比原文。[4]中将reason翻译为"据因",但我理解他想要表达的是“拒因”,有一些文字中用的是“拒因”,但这样翻译很不容易理解。再好比[4]中将fulfilled状态翻译为执行态, 后面中文语句中也很难以理解。[5]中尽量地将一些专用词汇没有翻译为中文,但错别字较多,行文不顺畅。本文参考了[4]与[5]的中文翻译,文中强调的must、must not突出翻译了出来,但尽量保留了原规范的章节编号,术语、状态和一些特定词汇不翻译为中文,直接采用英语反倒使得文字简洁易懂。html

下面是Promises/A+规范Version 1.1.1 /2014-05-05的中文翻译。前端


一个开放、健全且通用的 JavaScript Promise 标准。由开发者制定,供开发者参考。
git

Promise 表示一个异步操做的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 promise 的最终值(eventual value)或promise 不能fulfilled的缘由(reason)。github

本规范详细描述then方法的行为特色,全部遵循 Promises/A+ 规范实现的 promise 都可以本标准做为参照基础来实现then方法。规范应当是十分稳定的。Promise/A+ 组织会不断修订本规范,以解决一些新发现的边边角角问题,但所作的改动会是微小且向后兼容的。若是咱们要进行大规模或者向后不兼容的更新,咱们必定会在事先进行谨慎地考虑、详尽的探讨和严格的测试。web

从历史上说,本规范其实是澄清了以前 Promise/A 规范 中建议的行为语句,扩展了这些建议中已成为事实上规范的行为,同时删减了原规范中一些不足以成为规范和有问题的部分。算法

最后,Promises/A+ 规范的核心不涉及如何建立、fulfill或reject promise,而是专一于提供一个可互操做的then方法。上述对于 promises 的操做方法未来在其余规范中可能会说起。api

1. 术语

1.1 "promise" 是一个拥有 then 方法的对象或函数,该方法的行为遵循本规范.promise

1.2“thenable”是一个定义了 then 方法的对象或函数.app

1.3“value”指任何 JavaScript 合法值(包括 undefined , thenable对象或promise对象).webapp

1.4“exception”是使用 throw 语句抛出的一个value。

1.5“reason”是表示promise状态为什么转换为rejected的一个value.

2. 需求

2.1. Promise状态

    Promise状态必须为pendingfulfilledrejected中的一种。

2.1.1. 当状态为pending时:

       2.1.1.1. 能够转换为fulfilled或rejected状态。

2.1.2. 当状态为fulfilled时:

       2.1.2.1. 必定不能转换为其余状态。

       2.1.2.2. 必须有一个value值,且必须不可改变

2.1.3. 当状态为rejected时:

   2.1.2.1. 必定不能转换为其余状态。

       2.1.2.2. 必须有一个reason,且必须不可改变。

    上述"必须不可改变“指的是恒等不变(immutable identity:便可用 === 判断相等),而不是意味着深不可变(deep immutability。译者注: 这里须要再研究下)。

2.2. then方法

    promise必须提供一个then方法,用于获取promise当前/最终value或reason。

    promise的then方法接受两个参数:

  promise.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. 当promise状态为fulfilled时必须被调用,promise的value做为第一个参数。

      2.2.2.2. 当promise状态为fulfilled以前必定不能被调用。

      2.2.2.3. 调用次数必定不能超过一次。

2.2.3.  若是 onRejected 是函数:

      2.2.3.1. 当promise状态为rejected时必须被调用,promise的reason做为第一个参数。

      2.2.3.2. 当promise状态转换为rejected以前必定不能被调用。

      2.2.3.3. 调用次数必定不能超过一次

2.2.4.  onFulfilled 和 onRejected 只有当执行上下文堆栈中仅包含平台代码[3.1]时才能够被调用。

2.2.5.  onFulfilled 和 onRejected 必须做为函数来调用(即没有 this 值)[3.2]

2.2.6.  对同一个promise能够调用屡次then方法,

      2.2.6.1. 若是/当promise状态为fulfilled时,必须按调用then方法的顺序依次执行 onFulfilled 回调函数。

      2.2.6.2. 若是/当promise状态为rejected时,必须按调用then方法的顺序依次执行 onRejected 回调函数。 

2.2.7. then方法必须返回一个promise[3.3]

promise2 = promise1.then(onFulfilled, onRejected);

      2.2.7.1. 若是 onFulfilled 或 onRejected 函数返回值为x,那么执行Promise resolution过程 [[Resolve]](promise2, x) 。

      2.2.7.2. 若是 onFulfilled 或 onRejected 函数抛出异常e,那么promise2状态为rejected, e 做为reason。

      2.2.7.3. 若是 onFulfilled 不是函数且promise1状态是fulfilled,那么promise2状态必须是fulfilled且与promise1的value相同。

      2.2.7.4. 若是 onRejected不是函数且promise1状态是rejected,那么promise2状态必须是rejected且与promise1的reason相同。

2.3. Promise resolution过程

     Promise resolution过程是一个抽象操做,须要输入一个promise和一个value,用 [[Resolve]](promise, x) 来表示。若是x是thenable对象,则尝试使promise接受x的状态,这里假定x的行为特性至少相似于一个promise;不然用value x来fulfill promise。

       这样处理then对象可使promise的实现有更好的互操做: 只要它们暴露出一个遵循Promises/A+规范的then方法。这样处理也使得遵循Promise/A+ 规范的实现能够与那些未完整遵循规范但then方法合理的实现能良好共存。

     [[Resolve]](promise, x) 按照下面步骤来运行:

2.3.1. 若是promise和x指向同一个对象,则reject promise而且用一个TypeError做为reason。

2.3.2. 若是x是一个promise实例,则以x的状态做为promise的状态[3.4]

  2.3.2.1. 若是x的状态为pending,那么promise的状态必须保持为pending,直到x的状态变为fulfilled或者rejected。

      2.3.2.2. 若是/当x的状态为fulfilled,则用一样的value来fulfill promise。

      2.3.2.3. 若是/当x的状态为rejected,则用一样的reason来reject promise

2.3.3. 不然,若是x是一个对象或函数

      2.3.3.1. 将x.then赋值给then[3.5]

      2.3.3.2. 若是在获取x.then属性时抛出一个异常e,则用e做为reason来reject promise

      2.3.3.3. 若是then是函数类型,则以x做为then函数内部的this指针,以resolvePromise为第一个参数,rejectPromise为第二个参数,调用then函数。这里:

        2.3.3.3.1. 若是/当resolvePromise被调用且value为y,则执行[[Resolve]](promise, y) 。

            2.3.3.3.2. 若是/当rejectPromise被调用且reason为r,则用r来reject promise。

            2.3.3.3.3. 若是 resolvePromise 和 rejectPromise都被调用,或者屡次调用的参数都相同,则优先采用首次调用并忽略剩下的调用。

            2.3.3.3.4. 若是调用then方法抛出一个异常e,

      2.3.3.4.1. 若是resolvePromise或rejectPromise已经被调用,则忽略该异常。

      2.3.3.4.2. 不然用e做为reason来reject promise。

       2.3.3.4. 若是then不是函数类型,用x来fulfill promise

2.3.4.若是x不是对象或函数,用x来fulfill promise

    若是一个promise是被一个循环的 thenable 链中的thenable对象resolve,而 [[Resolve]](promise, thenable) 的递归性质又使得 [[Resolve]](promise, thenable) 被再次调用,根据上述算法将会陷入无限递归之中。本规范不强制要求,但鼓励实现者检测这样的递归是否存在,若检测到存在则以一个TypeError为reason来reject promise[3.6]。

3. 备注

3.1. 这里的“平台代码”是指引擎、执行环境和promise实现代码。实践中,这个需求是确保 onFulfilled 和 onRejected 函数为异步执行,且应该在 then 方法被调用的那一轮事件循环以后,在一个新的堆栈中执行。这个事件队列能够采用“宏任务(macro-task)”机制(诸如经过 setTimeout 或 setImmediate )或者“微任务(micro-task)”机制(诸如经过 MutationObserver 或 process.nextTick )来实现。因为 promise 的实现代码被视为平台代码,所以实现代码自身能够包含一个任务调度队列或者handler被调用的跳板


译者注: 这里说起了 macro-task 和 micro-task 两个概念,可参见[6], [7]。当挂起任务时,JS 引擎会将全部任务按照类别分到这两个队列中,事件循环的每一轮都要处理来自 macro-task 队列(这个队列在 WHATWG specification中被称为任务队列)的一个任务,该任务执行完毕后取出 micro-task 队列中的全部任务顺序执行;以后再是下一轮取出一个macro-task 任务,取出全部的micro-tasks,从而周而复始。

但这样可能会致使当micro-task 队列中全部任务运行完成,执行下一个macro-task 任务时已通过去了很长时间,这会致使UI被阻塞等各类异常。Node.js中process.nextTick函数会在micro-tasks中排队, 有一个内在保护机制process.maxTickDepth能够避免长时间阻塞,这个值缺省为1000, 当这个时间到后就再也不处理micro-tasks,而是开始处理下一个macro-task

一般, 当须要以同步方式来作异步访问时使用micro-tasks(即当即执行这一micro任务),不然使用macro-tasks.

举例:

macro-tasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-tasks: process.nextTick, Promises, Object.observe, MutationObserver


3.2. 在strict模式下this指针为undefined,而在sloppy模式下this指针为全局对象。

3.3. 代码实如今知足全部需求点的状况下能够容许 promise2 === promise1 。每一个实现都要有文档说明其是否容许以及在何种条件下容许 promise2 === promise1。

3.4. 通常来讲,若是按照当前实现,只知道x是个真正的 promise 。这一规则容许那些特例实现 接受 遵循规范要求的Promises的状态。

3.5.  这步咱们先是存储了一个指向 x.then 的引用,接下来测试该引用,而后调用该引用,以免屡次访问 x.then 属性。这种预防措施确保了访问该属性的一致性,由于其值可能在检索调用时被改变。

3.6. 实现不该当对thenale链的深度有任何限制, 不该当假定超过该限制就会无限递归。只有真正的循环递归才应能致使 TypeError 异常;若是一条无限长的链上有不一样的thenable,那么不断递归就是正确的行为。

参考资料:

[1] Promises/A+, https://promisesaplus.com/

[2] Differences from Promises/A, https://promisesaplus.com/differences-from-promises-a

[3] Conformant Implementations, https://promisesaplus.com/implementations

[4] Promise A+ 规范 中文翻译, http://malcolmyu.github.io/malnote/2015/06/12/Promises-A-Plus/

[5] 前端翻译:Promises/A+规范, 肥仔John, http://www.cnblogs.com/fsjohnhuang/p/4139172.html

[6] Difference between microtask and macrotask within an event loop context, http://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context

[7] Promise进阶介绍+原生实现, http://wengeezhang.com/?p=11

相关文章
相关标签/搜索