Promise then方法的细节(Promises/A+规范完整翻译)
2017-12-28 19:58
197 查看
查看了一些Promise相关的教程,发现基本上都只介绍了then、catch、Promise.resolve、Promise.reject、Promise.all、Promise.race等方法的使用,而很少详细介绍链式调用then方法时的细节。而 ES6 Promise 的规范又超级长,看起来难免会费些时间。
偶然发现了 Promises/A+ 规范,这个规范较为简短,并主要介绍了then方法的规范。而 ES6 Promise 也是基于 Promises/A+ 规范而来,因此通过了解 Promises/A+ 规范便可以很深入地了解到在链式调用then方法时的一些细节。
故对 Promises/A+ 规范进行了全篇翻译,其原文地址为https://promisesaplus.com/,本人的翻译如下:
一个 promise 代表了一个异步操作的最终结果。与一个 promise 交互的主要方式是通过它的
本规范详细描述了
从历史上来讲,Promises/A+ 规范阐明了更早出现的 Promises/A 提议,并扩展了它以涵盖 promise 的实际行为,也去掉了一些不足之处或有问题的地方。
最终,核心 Promises/A+ 规范并不涉及如何
1.2. “thenable”指一个拥有
1.3. “value”指任意合法的JavaScript值(包括
1.4. “exception”指用
1.5. “reason”指表明promise为何被rejected的一个值。
2.1.1. 当处于
2.1.1.1. 可以转变为
2.1.2. 当处于
2.1.2.1. 不可再转变为任何其他状态。
2.1.2.2. 必须有一个
2.1.3. 当处于
2.1.3.1. 不可再转变为任何其他状态。
2.1.3.2. 必须有一个
这里的“不可变”对于对象等值来说是指向的对象不可变,而这并不意味着此对象的属性不可变(译者注:例如一个promise的值为{a:1},若将其属性a的值改为2,也是允许的)。
2.2
一个promise必须提供一个
一个promise的
2.2.1.
2.2.1.1. 若
2.2.1.2. 若
2.2.2. 若
2.2.2.1. 当
2.2.2.2. 在
2.2.2.3. 此函数被调用的次数不可超过一次。
2.2.3. 若
2.2.3.1. 当
2.2.3.2. 在
2.2.3.3. 此函数被调用的次数不可超过一次。
2.2.4. 只有当 执行上下文栈 中只包含平台代码(platform code)时
2.2.5.
2.2.6. 在同一个promise上可以多次调用
2.2.6.1. 当
2.2.6.2. 当
2.2.7.
2.2.7.1. 如果
2.2.7.2. 如果
2.2.7.3. 如果
这种处理
执行
2.3.1. 如果
2.3.2. 如果
2.3.2.1. 如果
2.3.2.2. 当
2.3.2.3. 当
2.3.3. 如果
2.3.3.1. 令
2.3.3.2. 如果访问
2.3.3.3. 如果
2.3.3.3.1. 如果或当
2.3.3.3.2. 如果或当
2.3.3.3.3. 如果
2.3.3.3.4. 如果调用
2.3.3.3.4.1 如果
2.3.3.3.4.2 否则,以
2.3.3.4. 如果
2.3.4. 如果
如果一个promise被一个
3.2. 这里指的是在 严格模式(strict mode) 下,
3.3. 即使一个promise实现满足本规范所有要求,这个实现也可能允许出现
3.4. 一般来说,只有当
3.5. 这种首先保存
偶然发现了 Promises/A+ 规范,这个规范较为简短,并主要介绍了then方法的规范。而 ES6 Promise 也是基于 Promises/A+ 规范而来,因此通过了解 Promises/A+ 规范便可以很深入地了解到在链式调用then方法时的一些细节。
故对 Promises/A+ 规范进行了全篇翻译,其原文地址为https://promisesaplus.com/,本人的翻译如下:
Promises/A+
为实现者提供一个健全的、可互操作的 JavaScript promise 的开放标准。一个 promise 代表了一个异步操作的最终结果。与一个 promise 交互的主要方式是通过它的
then方法向 promise 注册回调函数(callbacks),回调函数则用来接收 promise 的的最终值(eventual value)或者promise失败(cannot be fulfilled)的原因。
本规范详细描述了
then方法的行为,提供了一个可互操作(interoperable)的基础,所有遵循 Promises/A+ 规范的promise实现都可以依赖这个基础。因此,可以认为本规范是非常稳定的。尽管 Promises/A+ 组织可能会偶尔对本规范进行小幅的且向后兼容的修订以处理一些新发现的极端情况,我们只会在谨慎考虑、讨论和测试后才会向规范中加入较大的或向后不兼容的改动。
从历史上来讲,Promises/A+ 规范阐明了更早出现的 Promises/A 提议,并扩展了它以涵盖 promise 的实际行为,也去掉了一些不足之处或有问题的地方。
最终,核心 Promises/A+ 规范并不涉及如何
创建、fulfill 或者 rejectpromises,而是选择专注于提供一个可互操作的
then方法。在将来的一些伴随规范中可能会涉及如何
创建、fulfill 或者 rejectpromises。
1. 术语
1.1. “promise”指一个拥有then方法的对象或函数,且该
then方法的行为符合本规范。
1.2. “thenable”指一个拥有
then方法的对象或函数。
1.3. “value”指任意合法的JavaScript值(包括
undefined,一个thenable或一个promise)。
1.4. “exception”指用
throw抛出的异常。
1.5. “reason”指表明promise为何被rejected的一个值。
2. 规范要求
2.1 Promise状态
一个promise必须处于以下三种状态之一:pending(未决议状态),fulfilled(成功状态) 或 rejected(失败状态)。2.1.1. 当处于
pending状态时,一个promise:
2.1.1.1. 可以转变为
fulfilled状态或
rejected状态。
2.1.2. 当处于
fulfilled状态时,一个promise:
2.1.2.1. 不可再转变为任何其他状态。
2.1.2.2. 必须有一个
value,且值不可变。
2.1.3. 当处于
rejected状态时,一个promise:
2.1.3.1. 不可再转变为任何其他状态。
2.1.3.2. 必须有一个
reason,且值不可变。
这里的“不可变”对于对象等值来说是指向的对象不可变,而这并不意味着此对象的属性不可变(译者注:例如一个promise的值为{a:1},若将其属性a的值改为2,也是允许的)。
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. 只有当 执行上下文栈 中只包含平台代码(platform code)时
onFulfilled或
onRejected才可以被调用。[详情见3.1]
2.2.5.
onFulfilled和
onRejected必须以函数方式被调用,且没有
this值(译者注: 以函数方式调用是指
onFulfilled(v)这种方式,不可用
new onFulfilled()方式或
onFulfilled.call()/
onFulfilled.apply()方式)。[详情见3.2]
2.2.6. 在同一个promise上可以多次调用
then方法。
2.2.6.1. 当
promise变为或已处于
fulfilled时,所有
onFulfilled回调必须按照其通过
then注册的顺序被执行。
2.2.6.2. 当
promise变为或已处于
rejected时,所有
onRejected回调必须按照其通过
then注册的顺序被执行。
2.2.7.
then方法必须返回一个promise。[详情见3.3]
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1. 如果
onFulfilled或
onRejected返回了一个值
x, 则执行Promise Resolution Procedure(Promise决议程序)
[[Resolve]](promise2, x)。
2.2.7.2. 如果
onFulfilled或
onRejected抛出了一个异常
e,则
promise2必须被rejected,且以
e作为reason。
2.2.7.3. 如果
onRejected不是函数且
promise1已处于
rejected状态,则
promise2必须以
promise1的
reason被
rejected。
2.3 Promise Resolution Procedure(Promise决议程序)
Promise Resolution Procedure 是以一个promise和一个value为输入的抽象操作,我们将其表示为[[Resolve]](promise, x)。如果
x是一个
thenable且行为有几分像promise时,Promise Resolution Procedure 会试图让
promise变为与
x相同的状态。否则,
promise会被决议程序以
x为值
fulfilled。
这种处理
thenable的方式可以使不同的promise实现之间可以互操作,只要这些实现对外暴露了遵循
Promises/A+规范的
then方法即可。这种方式也使得遵循
Promises/A+规范的实现可以“同化”那些没有遵循
Promises/A+规范但具备合理的
then方法的promise实现。
执行
[[Resolve]](promise, x)需运行以下步骤:
2.3.1. 如果
promise和
x指向同一个对象,则 reject
promise并且以
TypeError作为
reason。
2.3.2. 如果
x是一个promise,则采用
x的状态 [详情见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. 令
then指向
x.then。[详情见3.5]
2.3.3.2. 如果访问
x.then属性导致抛出异常
e,则以
e为
reason来 reject
promise。
2.3.3.3. 如果
then是一个函数,则调用它,并且以
x作为
this,以
resolvePromise作为第一个参数,以
rejectPromise作为第二个参数,且:
2.3.3.3.1. 如果或当
resolvePromise以一个值
y被调用了,则执行
[[Resolve]](promise, y)。
2.3.3.3.2. 如果或当
rejectPromise以一个值
r被调用了,则以
r来 reject
promise。
2.3.3.3.3. 如果
resolvePromise和
rejectPromise都被调用了,或者某个已被被多次调用了,则首次发生的调用生效,其余所有调用都被忽略。
2.3.3.3.4. 如果调用
then抛出异常
e:
2.3.3.3.4.1 如果
resolvePromise或
rejectPromise已经被调用过了,则忽略这个异常。
2.3.3.3.4.2 否则,以
e来 reject
promise。
2.3.3.4. 如果
then不是函数,则以
x来 fulfill
promise。
2.3.4. 如果
x既不是对象也不是函数,则以
x来 fulfill
promise。
如果一个promise被一个
thenable决议,且此
thenable在一个循环的thenable链中,
[[Resolve]](promise, thenable)的递归特性会导致
[[Resolve]](promise, thenable)再次被调用,根据上面的算法,这会导致无限递归。因此我们鼓励(但不强制要求)promise实现时能检测无限递归,并在出现无限递归时以一个
TypeError来 reject
promise。
3. 说明
3.1. 这里的“平台代码(platform code)”意为JS引擎、JS执行环境和实现promise的代码。实际上,这条要求是为了确保在then被调用的那次事件循环之后,并且是在一个新的调用栈里异步地执行
onFulfilled和
onRejected。这种方式可以通过 “宏任务(macro-task)” 原理实现,比如
setTimeout或
setImmediate,或通过 “微任务(micro-task)” 原理实现,比如
MutationObserver或
process.nextTick。既然promise的实现被认为是平台代码,那么它本身可能包含一个任务调度队列或者一个用于调用函数的“trampoline”。
3.2. 这里指的是在 严格模式(strict mode) 下,
this在
onFulfilled和
onRejected中值为
undefined;在 非严格模式 下,
this指向全局对象(global object)。
3.3. 即使一个promise实现满足本规范所有要求,这个实现也可能允许出现
promise2 === promise1。每个promise实现应当在文档中说明该实现中是否会出现
promise2 === promise1的情况以及在什么情况下会出现。
3.4. 一般来说,只有当
x来自当前的实现时,才能知道
x是一个真正的promise。对于一个已知其符合当前实现的promise,这个条款允许使用特定于实现的方式来 采用(adopt) 该promise的状态。
3.5. 这种首先保存
x.then的引用,然后测试此引用,再调用此引用的处理,避免了对
x.then属性的多次访问。这种预防措施在面对一些特殊访问器时十分重要,因为有的访问器每次访问都会导致其值的改变。
相关文章推荐
- alibaba java coding Guidelines阿里巴巴代码规范指南插件的集成方法以及些小细节
- Ruby 编程规范【完整翻译】
- 异步方法细节的文章.有时间翻译一下, I
- 关于Qt5.4.0的中文翻译不“完整”的解决方法
- Android 一个TextView中设置文字不同字体大小和颜色的最完整方法
- Asp.Net数据库编程-10条最优方法[翻译]
- 针对2008 激活新方法的新使用,以保证重启后功能依然完整
- 批处理(bat)实现全盘搜索指定文件获取其完整路径方法大全
- 分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节
- 细节问题:String 的split方法
- 用VS2010构建MASM的编程环境,开始使用MASM(翻译自《Inetl汇编语言程序设计》一书的作者Kip R. Irvine的文章Getting Started with MASM),两种方法搭建IA-32汇编设计环境
- 方法的命名规范 带参数的类的声明实现
- 泛型:更好的匹配方法【翻译】
- 【代码阅读的方法与实践】第7章 编码规范和约定
- Objective-C编码规范[不定期更新细节]
- php mssql2000 text字段 被截断读取不完整的问题解决方法
- 关于drawRect:方法apple官方文档的翻译
- drupal7 导入翻译时出错解决方法
- Servlet3.1规范翻译——转发请求
- 编码规范--方法注释