Promise/A+规范-翻译
Promise 表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 promise 的终值或本 promise 不能执行的原因。
本规范详细列出了 then 方法的执行过程,所有遵循 Promises/A+ 规范实现的 promise 均可以本标准作为参照基础来实施 then 方法。因而本规范是十分稳定的。尽管 Promise/A+ 组织有时可能会修订本规范,但主要是为了处理一些特殊的边界情况,且这些改动都是微小且向下兼容的。如果我们要进行大规模不兼容的更新,我们一定会在事先进行谨慎地考虑、详尽的探讨和严格的测试。
从历史上说,本规范实际上是把之前 Promise/A 规范 中的建议明确成为了行为标准:我们一方面扩展了原有规范约定俗成的行为,一方面删减了原规范的一些特例情况和有问题的部分。
最后,核心的 Promises/A+ 规范不设计如何创建、解决和拒绝 promise,而是专注于提供一个通用的 then 方法。上述对于 promises 的操作方法将来在其他规范中可能会提及。
1. 术语
1.1. promise: 一个拥有符合这个规范的行为的then方法的对象或函数。
1.2. thenable: 定义了一个then方法的对象或函数。
1.3. 值(value): 任意合法的JavaScript值(包括undefined,thenable,promise)。
1.4. 异常(exception): 使用throw语句抛出的一个值
1.5. 原因(reason): 表示promise为什么被拒绝的一个值
2. 必要条件
2.1. Promise 状态
promise必须是这三个状态中的一种:等待态pending,解决态fulfilled或拒绝态rejected
2.1.1 当一个promise处于等待状态的时候:
- 2.1.1.1 可能变为解决或者拒绝状态。
2.1.2. 当一个promise处于解决状态的时候:
2.1.2.1. 一定不能转换为任何其它状态
2.1.2.2. 必须有一个不能改变的值
2.1.3. 当一个promise处于拒绝状态的时候:
2.1.3.1. 一定不能转换为任何其它状态
2.1.3.2. 必须有一个不能改变的值
在这里,"一定不能改变"意味着不变的身份(例如 ===),但是并不意味着深度不可变性。(译注者:这里应该是说只要值的引用相同即可,并不需要引用中的每一个值都相等)
2.2. then 方法
Promise必须提供一个then方法来访问当前或最终的值或原因。
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被解决后调用,promise的值作为它的第一个参数。
2.2.2.2. 它一定不能在promise被解决前调用。
2.2.2.3. 它一定不能被调用多次。
2.2.3. 如果onRejected是一个函数
2.2.3.1. 它必须在promise被拒绝之后调用,用promise的原因作为它的第一个参数。
2.2.3.2. 它一定不能在promise被拒绝之前调用。
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被解决,所有相应的onFulfilled回调必须按照他们原始调用then的顺序执行
2.2.6.2. 如果promise被拒绝,所有相应的onRejected回调必须按照他们原始调用then的顺序执行
2.2.7. then必须返回一个promise [3.3]
promise2 = promise1.then(onFulfilled,onRejected)
2.2.7.1. 如果onFulfilled或onRjected返回一个值x,运行promise解决程序[Resolve]
2.2.7.2. 如果onFulfilled或onRejected抛出一个异常e,promise2必须用e作为原因被拒绝
2.2.7.3. 如果onFulfilled不是一个函数并且promise1被解决,promise2必须用与promise1相同的值被解决
2.2.7.4. 如果onRejected不是一个函数并且promise1被拒绝,promise2必须用与promise1相同的原因被拒绝
2.3. Promise解决程序
promise解决程序是一个抽象操作,它以一个promise和一个值作为输入,我们将其表示为[[Resolve]](promise, x)。如果x是一个thenable,它尝试让promise采用x的状态,并假设x的行为至少在某种程度上类似于promise。否则,它将会用值x解决 promise。
这种thenable的特性使得Promise的实现更具有通用性:只要其暴露一个遵循Promise/A+协议的then方法即可。这同时也使遵循Promise/A+规范的实现可以与那些不太规范但可用的实现能良好共存。
要运行[[Resolve]](promise, x),需要执行如下步骤:
2.3.1. 如果promise和x引用同一个对象,用一个TypeError作为原因来拒绝promise
2.3.2. 如果x是一个promise,采用它的状态:[3.4]
2.3.2.1. 如果x是等待态,promise必须保持等待状态,直到x被解决或拒绝
2.3.2.2. 如果x是解决态,用相同的值解决promise
2.3.2.3. 如果x是拒绝态,用相同的原因拒绝promise
2.3.3. 否则,如果x是一个对象或函数
2.3.3.1. 让then成为x.then。[3.5]
2.3.3.2. 如果检索属性x.then导致抛出了一个异常e,用e作为原因拒绝promise
2.3.3.3. 如果then是一个函数,用x作为this调用它。then方法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise:
2.3.3.3.1. 如果resolvePromise用一个值y调用,运行[[Resolve]](promise, y)。译者注:这里再次调用[Resolve],因为y可能还是promise
2.3.3.3.2. 如果rejectPromise用一个原因r调用,用r拒绝promise。译者注:这里如果r为promise的话,依旧会直接reject,拒绝的原因就是promise。并不会等到promise被解决或拒绝
2.3.3.3.3. 如果resolvePromise和rejectPromise都被调用,或者对同一个参数进行多次调用,那么第一次调用优先,以后的调用都会被忽略。译者注:这里主要针对thenable,promise的状态一旦更改就不会再改变。
2.3.3.3.4. 如果调用then抛出了一个异常e,
2.3.3.4.1. 如果resolvePromise或rejectPromise已经被调用,忽略它
2.3.3.4.2. 否则,用e作为原因拒绝promise
2.3.3.4. 如果then不是一个函数,用x解决promise
2.3.4. 如果x不是一个对象或函数,用x解决promise
如果promise用一个循环的thenable链解决,由于[[Resolve]](promise, thenalbe)的递归特性,最终将导致[[Resolve]](promise, thenable)被再次调用,遵循上面的算法将会导致无限递归。规范中并没有强制要求处理这种情况,但也鼓励实现者检测这样的递归是否存在,并且用一个信息丰富的TypeError作为原因拒绝promise。[3.6]
译者注:这里的循环thenable可能是指如下情况:
const obj = {
then:function() {
//...
}
}
obj.then.then = obj.then
这样obj对象中的then将会形成一个环,可以一直无限循环调用.then方法。(类似于window全局对象,window.window依旧是window自己)

由于resolvePromise方法中会对返回值(参数x)的类型进行判断,这样会导致返回值的类型一直为promise,即无限循环调用resolvePromise。
resolvePromise递归调用参考
3. 注解
3.1. 这里“平台代码”意味着引擎、环境以及promise的实现代码。在实践中,这需要确保onFulfilled和onRejected异步地执行,并且应该在then方法被调用的那一轮事件循环之后用新的执行栈执行。这可以用如setTimeout或setImmediate这样的“宏任务”机制实现,或者用如MutationObserver或process.nextTick这样的“微任务”机制实现。由于promise的实现被考虑为“平台代码”,因此在自身处理程序被调用时可能已经包含一个任务调度队列。
3.2. 严格模式下,它们中的this将会是undefined;在非严格模式,this将会是全局对象。
3.3. 假如实现满足所有需求,可以允许promise2 === promise1。每一个实现都应该记录是否能够产生promise2 === promise1以及什么情况下会出现promise2 === promise1。
3.4. 通常,只有x来自于当前实现,才知道它是一个真正的promise。这条规则允许那些特例实现采用符合已知要求的Promise的状态。
3.5. 这个程序首先存储x.then的引用,之后测试那个引用,然后再调用那个引用,这样避免了多次访问x.then属性。此类预防措施对于确保访问者属性的一致性非常重要,因为访问者属性的值可能在俩次检索之间发生变化。
3.6. 实现不应该在thenable链的深度上做任意限制,并且假设超过那个任意限制将会无限递归。只有真正的循环才应该引发一个TypeError;如果遇到一个无限循环的thenable,永远执行递归是正确的行为。
摘抄自:https://zhuanlan.zhihu.com/p/143204897(https://zhuanlan.zhihu.com/p/143204897)
Promise/A+规范-翻译的更多相关文章
- Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)
1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...
- 按照 Promise/A+ 规范逐行注释并实现 Promise
0. 前言 面试官:「你写个 Promise 吧.」 我:「对不起,打扰了,再见!」 现在前端越来越卷,不会手写 Promise 都不好意思面试了(手动狗头.jpg).虽然没多少人会在业务中用自己实现 ...
- Promise A 规范的一个简单的浏览器端实现
简单的实现了一个promise 的规范,留着接下来模块使用.感觉还有很多能优化的地方,有时间看看源码,或者其他大神的代码 主要是Then 函数.回调有点绕人. !(function(win) { fu ...
- 【javascript】Promise/A+ 规范简单实现 异步流程控制思想
——基于es6:Promise/A+ 规范简单实现 异步流程控制思想 前言: nodejs强大的异步处理能力使得它在服务器端大放异彩,基于它的应用不断的增加,但是异步随之带来的嵌套.难以理解的代码让 ...
- Go语言安全编码规范-翻译(分享转发)
Go语言安全编码规范-翻译 本文翻译原文由:blood_zer0.Lingfighting完成 如果翻译的有问题:联系我(Lzero2012).匆忙翻译肯定会有很多错误,欢迎大家一起讨论Go语言安全能 ...
- [转]MBTiles 1.2 规范翻译
MBTiles 1.2 可以参考超图的文档MBTiles扩展具体实现可以参考浅谈利用SQLite存储离散瓦片的思路和实现方法 mapbox提供了一个简单实现测试代码,github地址在这里https: ...
- 手写一款符合Promise/A+规范的Promise
手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看.如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的.主要 ...
- when 让你跳出异步回调噩梦 node.js下promise/A规范的使用
其实关于promise 的博客,前端时间专门写了一篇关于 promise 规范的文章,promise规范 让 javascript 中的异步调用更加人性化. 简单回忆下: promise/A规范定义的 ...
- Promise/A+规范
1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...
随机推荐
- 20、高可用数据同步工具drbd介绍
20.1.什么是drbd: 20.2.drbd的工作原理: 20.3.drbd的同步模式: 1.实时同步模式: 2.异步同步模式: 20.4.drbd生产应用场景: 1.生产场景中drbd常用于基于高 ...
- 手把手教会你远程Linux虚拟机连接以及配置pytorch环境。
出一期用于连接远程Ubuntu系统并配置pytorch环境的教学.2021-07-07 13:35:57- 现在的矿难导致显卡大幅度的涨价对很多要做深度学习领域的小伙伴们非常的不友好,配置设备固然要掏 ...
- Zoho Books十年发展历程
十年前,我们推出Zoho Books的时候,是为了全面解决企业面临的财务和会计方面的挑战.我们逐渐地从一开始的易用的中小企业在线会计工具,发展成为现在的解决企业复杂的财务挑战的解决方案,其中经历了很多 ...
- RabbitMQ重试机制
消费端在处理消息过程中可能会报错,此时该如何重新处理消息呢?解决方案有以下两种. 在redis或者数据库中记录重试次数,达到最大重试次数以后消息进入死信队列或者其他队列,再单独针对这些消息进行处理: ...
- webpack(8)vue组件化开发的演变过程
前言 真实项目开发过程中,我们都是使用组件化的去开发vue的项目,但是组件化的思想又是如何来的呢?下面就从开始讲解演变过程 演变过程1.0 一般情况下vue都是单页面开发,所以项目中只会有一个inde ...
- 一文读懂 .NET 中的高性能队列 Channel
介绍 System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能,线程安全等特点,它可以用来做消息队列,进行数据的生产和消费, 公 ...
- Spring Boot(一):如何使用Spring Boot搭建一个Web应用
Spring Boot Spring Boot 是Spring团队旗下的一款Web 应用框架 其优势可以更快速的搭建一个Web应用 从根本上上来讲 Spring Boot并不是什么新的框架技术 而是在 ...
- 家庭账本开发day09
编写数据表格的编辑操作,大体思路和删除操作一样 点击按钮,弹出修改项目,从父窗口获取已有的值赋给 弹出的子窗口中相应的值,在子窗口中点击提交,ajax请求 servlet修改.成功后重载表格,或者up ...
- [iconfont_dart]帮你快速生成Icon,再也不用手动写Icon方法
iconfont_dart iconfont to dart.Icon can be implemented by calling iconfont classname. iconfont转dart. ...
- File类与常用IO流第四章——IO字节流
一切文件在存储时,都是以二进制数字的形式保存的,都是一个一个字节.无论使用什么样的流对象,底层传输的始终是二进制数据. 字节输出流 OutputStream java.io.OutputStream ...