Promises/A+SpecificationTranslation&Learning原文翻译&学习笔记原文链接1.Terminology1.1“promise”是一个行为符合本规范的带有then方法的函数或对象。1.2“thenable”是定义了then方法的函数或对象。1.3“value”是一个合法的JavaScript值(值的类型包括undefined、thenable或promise)。1.4“异常”是使用throw语句抛出的值。1.5“原因”是一个值,用于指示承诺失败的原因。2.要求2.1Promise状态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。必须有一个值,不能更改。2.1.3当处于rejected状态时,promise:2.1.3.1不能转换到其他状态。2.1.3.2。必须有一个原因,这是无法改变的。在这里,“不可变”意味着不可变的特性(即===),但并不意味着“深度不变性”。“深度不变性”类似于引用类型上的const:constarr=[1];arr=[2];//未捕获的类型错误:赋值给常量variable.arr[0]=2;console.log(arr);//[2]promise示例:varvalue=[1];varp=Promise.resolve(value);p.then(a=>console.log(a));//[1]p.then(a=>console.log(a===value));//true//对值引用的修改只在当前then函数的块级作用域内有效。p.then(a=>{a=[2];console.log(a);});//[2]p.then(a=>console.log(a));//[1]//可以修改value中每一项的值。p.then(a=>{a[0]=2;console.log(a);});//[2]p.then(a=>console.log(a));//[2]p.then(a=>console.log(a===value));//true2.2then方法承诺必须提供一个then方法来访问其当前或最终值/原因。promise的then方法接受两个参数:promise.then(onFulfilled,onRejected)2.2.1onFulfilled和onRejected都是可选参数:2.2.1.1如果onFulfilled不是一个函数,应该忽略它。2.2.1.2如果onRejected不是一个函数,它应该被忽略。2.2.2如果onFulfilled是一个函数:2.2.2.1这个函数只能在promise状态变为fulfilled之后调用,它的第一个参数是promise的值。2.2.2.2在promise的状态变为fulfilled之前不能调用该函数。2.2.2.3该函数不能多次调用。2.2.3如果onRejected是一个函数:2.2.3.1这个函数只能在promise状态变成rejected之后调用,第一个参数是promise的原因。2.2.3.2在承诺状态变为拒绝之前,无法调用该函数。2.2.3.3该函数不能多次调用。2.2.4onFulfilled或onRejected在执行上下文堆栈仅包含“平台代码”之前不应被调用。(“平台代码”是指engine、environment、promise的实现代码,在实践中,这个需求保证onFulfilled和onRejected异步执行,事件循环结束后返回调用then函数的地方,重用新的堆栈。这可以通过宏任务机制(如setTimeout或setImmediate)或微任务机制(如MutationObserver或process.nextTick)来实现。由于promise的实现被视为平台代码,它本身可能包含任务调度队列或“蹦床”,其中调用处理程序)。2.2.5onFulfilled和onRejected应该作为函数调用(即没有这个值)。这里没有这个值意味着在严格模式下,这个值是未定义的,而在松散模式下,这个值是全局对象。2.2.6然后可以在同一个promise中多次调用。2.2.6.1当承诺实现时,所有相应的onFulfilled回调函数应按照调用then函数的原始顺序执行。2.2.6.2当promise被拒绝时,所有相应的onRejected回调函数应按照它们调用then函数的原始顺序执行。2.2.7then函数必须返回一个promise。如果代码实现满足所有要求,它应该允许promise2===promise1。每个实现都需要记录它是否允许promise2===promise1以及在什么条件下允许此结果。promise2=promise1.then(onFulfilled,onRejected);2.2.7.1如果onFulfilled或onRejected返回值x,允许Promise解析过程[[Resolve]](promise2,x)。2.2.7.2如果onFulfilled或者onRejected抛出异常e,那么promise2一定是rejected状态,reason是e。2.2.7.3如果onFulfilled不是一个函数并且promise1被fulfilled,promise2必须以与promise1相同的值被fulfilled。2.2.7.4如果onRejected不是函数,promise1处于rejected状态,promise2必须处于rejected状态,原因和promise1一样。2.3PromiseresolutionprocessPromiseresolutionprocess是一个以promise和value作为输入参数的抽象操作,我们记为[[Resolve]](promise,x)。如果x是thenable,它会尝试使promise呈现x的状态,前提是x的行为至少有点像promise。否则,promise将以值x实现。这种对thenable的处理允许promise进行互操作,只要它们公开符合Promises/A+的then方法。它还允许Promises/A+规范实现使用合理的then方法“同化”不兼容的实现。要运行[[Resolve]](promise,x),请按照以下步骤操作:2.3.1如果promise和x引用同一对象,则以TypeError作为原因拒绝该promise。2.3.2如果x是一个承诺,采用它的状态(一般来说,如果x来自当前实现,你只能确定x是一个真正的承诺。这个条款允许特定于实现的方法采用承诺的状态):2.3.2.1如果x处于pending状态,promise必须保持pending状态,直到x被履行或拒绝。2.3.2.2如果x处于fulfilled状态,执行与x相同值的promise。2.3.2.3如果x处于rejected状态,则拒绝与x具有相同reason值的promise。2.3.3否则,如果x是对象或函数,2.3.3.1将x.then赋值给then(先存储x.then的引用,然后测试引用,再调用引用。这个过程避免了对x的需要.then属性的多次访问。这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能在检索之间发生变化):2.3.3.2如果检索属性x.then导致抛出异常e被抛出,并且承诺被拒绝使用e作为原因。2.3.3.3如果then是一个函数,则使用x作为then函数的this,第一个参数调用resolvePromise,第二个参数调用rejectPromise:2.3.3.3.1如果调用resolvePromise,参数值为y,运行[[Resolve]](promise,y)。2.3.3.3.2如果以原因r调用rejectPromise,则拒绝以r的承诺。2.3.3.3.3如果同时调用了resolvePromise和rejectPromise,或者同一个参数多次调用,则先接受第一个调用,忽略其余调用。2.3.3.3.4如果调用then抛出异常e2.3.3.3.4.1如果调用resolvePromise或rejectPromise,则忽略这些调用。2.3.3.3.4.2否则,拒绝带有e的承诺。2.3.3.4如果then不是函数,则使用x来实现承诺。2.3.4如果x不是对象或函数,则使用x来实现承诺。如果promise由thenable循环链中的thenable解决(例如[[Resolve]](promise,thenable)的递归性质导致其自身被再次调用),遵循上述算法会导致无限递归。(我们)鼓励(但不要求)实现检测这种递归,并以信息拼写错误为由拒绝承诺(实现不应该对可用链的深度设置任意大小限制,并假设递归超出该限制将beinfinite是的。只有真正的循环才应该导致TypeError,如果你碰巧遇到不同thenable的无限链,那么永远递归是正确的行为)。参考资料Promises/A+Promise源码学习】第4部分——翻译理解PromiseA+规范什么是深度不变性?
