超直译PromiseA+

248 阅读7分钟

直译超直的那种翻译的 PromiseA+

1. 术语

  1. promise 是具有 then 方法并且符合本规范的对象或者函数
  2. thenable 是定义 then 方法的对象或者函数
  3. value 是任何合法的 javascript 值包括 undefined / promise 或者一个有 then 方法或者属性的对象
  4. exception 是一个被 throw 抛出的语句,常见的 throw new Error
  5. reason 是一个被 promise 拒绝的原因

2. 要求

2.1 promise state ( 状态 )

一个 promise 必须有三个状态 pending ( 等待 ) fulfilled ( 已完成 | 已实现 ) rejected ( 拒绝 )

2.1.1 当 promise 是 pending 时

有可能会转换成 fulfilled 有可能会转换成 rejected

2.1.2 当 promise 是 fulfilled 时

不能被转换成其他状态

必须有一个 value 且不能被改变

2.1.2 当 promise 是 rejected 时

不能被转换成其他状态

必须有一个 reason 且不能被改变

2.2 then 方法

一个 promise 必须有一个 then 方法用来获取最终的已完成的值或者拒绝的原因

promise 的 then 方法接受两个参数

promise.then(onfulfilled, onrejected)

2.2.1 这两个 onfulfilled onrejected

如果这两个参数的类型不是函数,那么就必须被忽略

2.2.2 如果 onfulfilled 是个函数

必须是在 promise 的状态变更为 fulfilled 时候才能调用,并且用已完成的 value 作为他的第一个参数

在 promise 状态未变更时不允许调用‘

不能多次调用

2.2.3 如果 onrejected 是个函数

必须是在 promise 的状态变更为 rejected 时候才能调用,并且用已拒绝的 reason 作为他的第一个参数

在 promise 状态未变更时不允许调用‘

不能多次调用

2.2.4 需要看 3.1 笔记

2.2.5 onfulfilled 和 onrejected 必须被当作普通函数调用没有被指定 this (详情看 3.2 笔记)

2.2.6 then 可能会被一个 promise 多次调用

let p1 = new Promise()

p1.then(onfulfilled, onrejected)

p1.then(onfulfilled, onrejected)

如果 promise 状态变更为已实现那么就需要顺序调用每个 onfulfilled

如果 promise 状态变更为已拒绝那么就需要顺序调用每个 onrejected

2.2.7 then 必须返回一个 promise ( 原因看 3.3笔记 )

let p1 = new Promise()

let p2 = p1.then(onfulfilled, onrejected)

// p2 类型就是 promise 对象

如果有一个 onfulfilled 或者 onrejected 有返回一个值 x 就运行 Promise Resolution Procedure ( 理解为一个处理 promise 问题的方法 )

let p1 = new Promise()

let p2 = p1.then(funtcion onfulfilled() {
	return 1
}, onrejected)

// 此时需要运行

function PromiseResolutionProcedure(promise2, x){
	// 此处的 x 就时 1
	// promise2 就是 then 函数返回的 promise
}

如果有一个 onfulfilled 或者 onrejected 有报错或者你认为是异常的异常 e ,则 promise2 就以这个 e 作为拒绝的 reason 并且状态转换成以拒绝

如果 then 的 onfulfilled 不是一个函数,并且这个时候 promise 状态已经转换为 已完成,那么 t hen 函数返回的 promise2 就以 promise1 的 value 作为 fullfilled 的值

如果 then 的 onrejected 不是一个函数,并且这个时候 promise 状态已经转换为 已拒绝,那么 t hen 函数返回的 promise2 就以 promise1 的 reason 作为 rejected 的值

2.3 The Promise Resolution Procedure

这个解决过程是一个抽象的过程,(抽象啥意思 黑人???)。如果 x 有 then 方法或者属性,那么就是说这个 x 有可能是个 promise 那么就用这个 x 的最终状态作为 promise2 的已完成的值

执行这个解决过程需要注意的步骤

2.3.1

如果 x 和 promise2 是同一个对象,一毛一样的那种,那就直接作为 promise2 的 以拒绝原因,这个原因是一个 TypeError 类型错误

2.3.2 如果 x 是一个 promise

let p1 = new Promise()

let p2 = p1.then(funtcion onfulfilled() {
	return new Promise() // x 就是这个 promise
}, onrejected)

如果 x 是一个 promise,x 的状态没有变更那么就一直保持 pendding 直到 x 状态扭转后才修改 promise 的状态

x 已完成 那么就用 x 已完成的 value 作为 promise2 的已完成值

x 已拒绝 那么就用 x 已拒绝的 reason 作为 promise2 的已拒绝 原因

2.3.2 如果 x 是一个 promise

let p1 = new Promise()

let p2 = p1.then(funtcion onfulfilled() {
	return new Promise() // x 就是这个 promise
}, onrejected)

如果 x 和 promise2 是同一个对象,一毛一样的那种,那就直接作为 promise2 的 以拒绝原因,这个原因是一个 TypeError 类型错误

2.3.3 如果 x 是个 promise 对象 看笔记 3.4

如果 x 状态为 pending, promise2 必须保持状态等 x 的状态变更为已兑现或者已拒绝,之后再修改自己的状态

如果当 x 状态为已兑现,promise2 就用这个已兑现的 value 作为他的 value

如果当 x 状态为已拒绝,promise2 就用这个已拒绝的 reason 作为他的 reason

2.3.4 如果 x 是个 对象或者函数 ( js 万物皆对象 )

获取 then 方法通过 x.then ( 获取x对象的方法或者属性/ 获取x函数对象的方法或者属性 )

let then = x.then

如果获取 then 方法出现了异常,那么 promise2 的状态就变更为以拒绝,reason 就是这个异常

try{
	let then = x.then
}catch(err){
	reject(err) // 这是 promise2 的 reject 哦
}

如果 then 是函数,使用 x 作为 then 函数的 this 指向,第一个参数 resolvePromise 第二个参数 rejectPromise

resolvePromise 获取到的值要走一遍那个神奇的 promise 解决过程, 这个值命名为y


try{
	let then = x.then
	if(typeof then === 'function'){
		then.call(x, function resolvePromise(y){
			// 这个 y 要走那个解决过程 因为这个 y 也有可能还是个 promise
		}, function rejectPromise(r){
			
		})
	}
}catch(err){
	reject(err) // 这是 promise2 的 reject 哦
}

如果 rejectPromise 获取到 x 已拒绝的 reason,那就是 promise2 的已拒绝的 reason

try{
	let then = x.then
	if(typeof then === 'function'){
		then.call(x, function resolvePromise(y){
			// 这个 y 要走那个解决过程 因为这个 y 也有可能还是个 promise
		}, function rejectPromise(r){
			reject(r)
		})
	}
}catch(err){
	reject(err) // 这是 promise2 的 reject 哦
}

如果同时调用 resolvePromise 或者 rejectPromise ,或者对同一个参数进行多次调用,那么第一次调用优先,其他调用都被忽略

let diaoyonglme = false // 默认没有调用
try{
	let then = x.then
	if(typeof then === 'function'){
		then.call(x, function resolvePromise(y){
			if(diaoyonglme) return
			diaoyonglme = true // 调用了就修改状态
			// 这个 y 要走那个解决过程 因为这个 y 也有可能还是个 promise
		}, function rejectPromise(r){
			if(diaoyonglme) return
			diaoyonglme = true // 调用了就修改状态
			reject(r)
		})
	}
}catch(err){ 
	// 如果调用 then 函数出了异常 promise2 就用这个异常作为已拒绝的 reason
	if(diaoyonglme) return
	diaoyonglme = true
	reject(err) // 这是 promise2 的 reject 哦
}

2.3.5 如果 x 不是个对象或者函数

promise2 就用这个 x 作为已兑现的 value

笔记

3.1 没理解,大佬们支持下

Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

3.2 严格模式下 this 会是 undefined,非严格模式下,this 是全局对象。

3.3 没理解,不是要求返回一个新的 promise 对象么,如果全等了,promise1的状态不是不能修改了么

Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions.

3.4 通常,你自己写的 promise 源码你大概能知道这个 x 是个 promise,但是实际中我可以导入三四个 promise 的库,然后这个 x 用别的库的 promise

3.5 存储下 then 函数的饮用,然后测试引用,然后调用引用的过程就避免了再次取值的过程中被篡改的风险,保证了 then 就是第一次获取到的那个 then,

x.then  // 1s前
x.then  // 1s后

// 这获取到的 then 可能不一样
// 这期间有可能会被改 x.then = balablablabla 然后就出错

3.6 没理解,大佬们支持下

Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.