PromiseA+的规范
讲解promiseA+规范前,先了解一些术语,以便在后续提到专有名词时有明确且统一的规范。
术语
- promise是一个有then方法的对象或者是函数,行为遵循本规范
- thenable是一个有then方法的对象或者函数
- value是promise状态成功时的值,也就是resolve的参数,包括各种数据类型,也包括undefined/thenable或者promise
- reason是promise状态失败时的值,也就是reject的参数,表示拒绝的原因
- exception是一个使用throw抛出的异常值
规范
接下来分几部分来讲解promiseA+规范
Promise State
promise应该有三种状态,要注意他们之间的流转关系
- pending
- 初始的状态,可改变
- 一个promise在resolve或者reject前都处于这个状态
- 可以通过resolve =>fulfilled状态
- 可以通过reject => rejected状态
- fulfilled
- 最终态,不可变
- 一个promise被resolve后变成这个状态
- 必须拥有一个value值
- rejected
- 最终态,不可变
- 一个promise被reject后会变成这个状态
- 必须拥有一个reason Tips:总结一下,就是promise的状态流转是这样的
- pending => resolve(value) => fulfilled
- pending => reject(reason) => rejected
then
promise应该提供一个then方法,用来访问最终的结果,无论是value还是reason
promise.then(onFulfilled,onRejected)
- 参数要求
- onFulfilled 必须是函数类型, 如果不是函数, 应该被忽略
- onRejected 必须是函数类型, 如果不是函数, 应该被忽略
- onFulfilled 特性
- 在promise变成 fulfilled 时,应该调⽤ onFulfilled, 参数是value
- 在promise变成 fulfilled 之前, 不应该被调⽤
- 只能被调⽤⼀次(所以在实现的时候需要⼀个变量来限制执⾏次数)
- onRejected 特性
- 在promise变成 rejected 时,应该调⽤ onRejected, 参数是reason
- 在promise变成 rejected 之前, 不应该被调⽤
- 只能被调⽤⼀次(所以在实现的时候需要⼀个变量来限制执⾏次数)
- onFulfilled 和 onRejected 应该是微任务
- 这⾥⽤queueMicrotask来实现微任务的调⽤
- then⽅法可以被调⽤多次
- promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执⾏, 也就 是按照注册顺序执⾏(所以在实现的时候需要⼀个数组来存放多个onFulfilled的回调)
- promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执⾏, 也 就是按照注册顺序执⾏(所以在实现的时候需要⼀个数组来存放多个onRejected的回调)
- 返回值
- then应该返回一个promise
promise2 = promise1.then(onFulfilled,onRejected);
- onFulfilled 或 onRejected 执⾏的结果为x, 调⽤ resolvePromise( 这⾥⼤家可能难以理 解, 可以先保留疑问, 下⾯详细讲⼀下resolvePromise是什么东⻄ )
- 如果 onFulfilled 或者 onRejected 执⾏时抛出异常e, promise2需要被reject
- 如果 onFulfilled 不是⼀个函数, promise2 以promise1的value 触发fulfilled
- 如果 onRejected 不是⼀个函数, promise2 以promise1的reason 触发rejected
- resolvePromise
resolvePromise(promise2, x, resolve, reject)
- 如果 promise2 和 x 相等,那么 reject TypeError
- 如果 x 是⼀个 promsie 如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected. 如果 x 被 fulfilled, fulfill promise with the same value. 如果 x 被 rejected, reject promise with the same reason
- 如果 x 是⼀个 object 或者 是⼀个 function let then = x.then. 如果 x.then 这步出错,那么 reject promise with e as the reason. 如果 then 是⼀个函数,then.call(x, resolvePromiseFn, rejectPromise) resolvePromiseFn 的 ⼊参是 y, 执⾏ resolvePromise(promise2, y, resolve, reject); rejectPromise 的 ⼊参是 r, reject promise with r. 如果 resolvePromise 和 rejectPromise 都调⽤了,那么第⼀个调⽤优先,后⾯的调⽤忽 略。 如果调⽤then抛出异常e 如果 resolvePromise 或 rejectPromise 已经被调⽤,那么忽略 则,reject promise with e as the reason 如果 then 不是⼀个function. fulfill promise with x
一步步实现一个Promise
- 平常⽤promise的时候, 是通过new关键字来new Promise(), 所以咱们应该⽤构造函数或者class 来实现. 都2021年了, 咱们就⽤class来实现⼀下吧
class Mpromise{
constructor(){
}
}
- 定义三种状态类型
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
- 设置初始状态
class Mpromise{
constructor(){
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
}
}
- resolve和reject方法
- 根据刚才的规范, 这两个⽅法是要更改status的, 从pending改到fulfilled/rejected
- 注意两个函数的⼊参分别是value 和 reason
class MPromise {
constructor() {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
};
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
};
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
}
- 是不是发现咱们的promise少了⼊参, 咱们来加⼀下
- ⼊参是⼀个函数, 函数接收resolve和reject两个参数
- 注意在初始化promise的时候, 就要执⾏这个函数, 并且有任何报错都要通过reject抛出去
class MPromise {
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this),this.reject.bind(this))
} catch (e) {
this.reject(e)
}
};
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
};
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
}
- 接下来实现关键的then方法
- then接收两个参数, onFulfilled 和 onRejected
then(onFulfilled,onRejected) {}
- 检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者 reason
isFunction(param){
return typeof param==='function';
};
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
};
- 要知道.then的返回值整体是⼀个promise, 所以咱们先⽤promise来包裹⼀下, 其他逻辑待会 再实现
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {});
return promise2;
};
- 根据当前promise的状态,调用不同的函数
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {
switch (this.status) {
case FULFILLED:{
realOnFulfilled();
break;
}
case REJECTED:{
realOnRejected();
break;
}
}
});
return promise2;
};
- 提问:如果这样写, 是在then函数被调⽤的瞬间就会执⾏. 那这时候如果 status还没变成fulfilled或者rejected怎么办, 很有可能还是pending的. 所以我们需要⼀个状 态的监听机制, 当状态变成fulfilled或者rejected后, 再去执⾏callback
- 那么我们⾸先要拿到所有的callback, 然后才能在某个时机去执⾏他. 新建两个数组, 来分别 存储成功和失败的回调, 调⽤then的时候, 如果还是pending就存⼊数组
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {
switch (this.status) {
case FULFILLED:{
realOnFulfilled();
break;
}
case REJECTED:{
realOnRejected();
break;
}
case PENDING:{
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
}
}
});
return promise2;
};
- 在status发⽣变化的时候, 就执⾏所有的回调. 这⾥咱们⽤⼀下es6的getter和setter. 这样更 符合语义, 当status改变时, 去做什么事情. (当然也可以顺序执⾏, 在给status赋值后, 下⾯再 加⼀⾏forEach)
_status = PENDING;
get status () {
return this._status;
}
set status(newStatus){
this._status = newStatus;
switch (newStatus){
case FULFILLED:{
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value);
});
break;
}
case REJECTED:{
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reson);
});
break;
}
}
}
- then的返回值,⾯只是简单说了下, then的返回值是⼀个Promise, 那么接下来具体讲⼀下返回promise的 value和reason是什么
- 如果 onFulfilled 或者 onRejected 抛出⼀个异常 e ,则 promise2 必须拒绝执⾏,并返回拒 因 e。(这样的话, 我们就需要⼿动catch代码,遇到报错就reject)
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {
const fulfilledMicrotask = () => {
try{
realOnFulfilled(this.value)
} catch (e){
reject(e)
}
}
const rejectedMicrotask = () => {
try{
realOnRejected(this.reason)
} catch (e){
reject(e)
}
}
switch (this.status) {
case FULFILLED:{
fulfilledMicrotask();
break;
}
case REJECTED:{
rejectedMicrotask();
break;
}
case PENDING:{
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
}
}
});
return promise2;
};
- 如果 onFulfilled 不是函数且 promise1 成功执⾏, promise2 必须成功执⾏并返回相同 的值
- 如果 onRejected 不是函数且 promise1 拒绝执⾏, promise2 必须拒绝执⾏并返回相同 的据因。 需要注意的是,如果promise1的onRejected执⾏成功了,promise2应该被resolve 这⾥咱们其实已经在参数检查的时候做过了, 也就是这段代码
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
- 如果 onFulfilled 或者 onRejected 返回⼀个值 x ,则运⾏resolvePromise⽅法
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {
const fulfilledMicrotask = () => {
try{
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
}
const rejectedMicrotask = () => {
try{
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
}
switch (this.status) {
case FULFILLED:{
fulfilledMicrotask();
break;
}
case REJECTED:{
rejectedMicrotask();
break;
}
case PENDING:{
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
}
}
});
return promise2;
};
- 实现resolvePromise
resolvePromise(promise2, x, resolve, reject){
// 如果 newPromise 和 x 指向同⼀对象,以 TypeError 为据因拒绝执⾏ newPromise
// 这里为了防止死循环
if(promise2 === x){
return reject( new TypeError('The promise and the return value are the same'))
}
if(x instanceof MPromise){
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执⾏x,如果执⾏的时候拿到⼀个y,还要继续解析y
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if (typeof x === 'object' || this.isFunction(x)){
// 如果 x 为对象或者函数
if( x===null ){
// null也会被判断为对象
return resolve(x);
}
let then =null;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error){
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error)
}
// 如果 then 是函数
if(this.isFunction(then)){
let called = false;
// 将 x 作为函数的作⽤域 this 调⽤
// 传递两个回调函数作为参数,第⼀个参数叫做 resolvePromise ,第⼆个参数叫做 rejectPromise
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调⽤,则运⾏ resolvePromise
(y) => {
// 需要有⼀个变量called来保证只调⽤⼀次
if(called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调⽤,则以据因 r 拒绝 promise
(r) => {
if(called) return;
called = true;
reject(r);
}
)
} catch (error){
// 如果调用 then 方法就抛出异常 e;
if(called) return;
// 否则以e为据因拒绝promise
reject(error)
}
} else {
// 如果then不是函数,以x 为参数执行promise
resolve(x)
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执⾏ promise
resolve(x)
}
}
- onFulfilled 和 onRejected 是微任务,需要用window自带的queueMicrotask函数来处理
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try{
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
})
}
const rejectedMicrotask = () => {
queueMicrotask(() => {
try{
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
})
}
- 补充catch方法
catch (onRejected) {
return this.then(null, onRejected)
}
- promise.resolve
- 将现有对象转为Promise对象,如果 Promise.resolve ⽅法的参数,不是具有 then ⽅法的对 象(⼜称 thenable 对象),则返回⼀个新的 Promise 对象,且它的状态为fulfilled。 注意这是⼀个静态⽅法, 因为咱们是通过Promise.resolve调⽤的, ⽽不是通过实例去调⽤的
static resolve (value){
if(value instanceof MPromise){
return value;
}
return new MPromise((resolve) => {
resolve(value)
})
}
- promise.reject
- 返回⼀个新的Promise实例,该实例的状态为rejected。Promise.reject⽅法的参数reason, 会被传递给实例的回调函数
static reject (reason) {
return new MPromise((resolve,reject)=>{
reject(reason)
})
}
- promise.race的实现
const p = Promise.race([p1,p2,p3]);
- 该方法是将多个Promise实例,包装成一个新的promise实例。
- 只要p1、p2、p3 之中有一个实例率先改变状态,p的状态就跟着改变,那个率先改变的Promise实例的返回值,就传递给p的回调函数
static race(promiseList){
return new MPromise((resolve,reject)=>{
const length = promiseList.length;
if(length===0){
return resolve();
}else{
for(let i=0;i<length;i++){
MPromise.resolve(promiseList[i]).then(
(value)=>{
return resolve(value);
},
(reason)=>{
return reject(reason);
}
)
}
}
})
}
- promise.all的实现
- promise.all(iterable)方法返回一个promise实例,此实例在iterable参数内所有的promise都完成(resolve),或者参数中不含promise时,回调完成(resolve)
- 如果参数中promise中有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个promise的结果
static all(promises){
return new MPromise((resolve,reject)=>{
if(!Array.isArray(promises)){
return reject(new TypeError('arguments must be Array'));
}
let count=0;
let newValues= new Array(promises.length);
for(let i=0;i<promises.length;i++){
MPromise.resolve(promises[i]).then(
(value)=>{
count++;
newValues[i]=value;
if(count === promise.length){
return resolve(newValues)
}
},
(reason)=>{
return reject(reason);
}
)
}
})
}
完整代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MPromise {
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this),this.reject.bind(this))
} catch (e) {
this.reject(e)
}
};
// 申明的变量
_status = PENDING;
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
};
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
// 判断是否是函数
isFunction(param){
return typeof param==='function';
};
get status () {
return this._status;
}
set status(newStatus){
this._status = newStatus;
switch (newStatus){
case FULFILLED:{
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value);
});
break;
}
case REJECTED:{
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reson);
});
break;
}
}
}
// then方法
then(onFulfilled,onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled :
(value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected :
(reason) => {
throw reason
};
const promise2 = new MPromise((resolve, reject)=> {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try{
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
})
}
const rejectedMicrotask = () => {
queueMicrotask(() => {
try{
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e){
reject(e)
}
})
}
switch (this.status) {
case FULFILLED:{
fulfilledMicrotask();
break;
}
case REJECTED:{
rejectedMicrotask();
break;
}
case PENDING:{
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
}
}
});
return promise2;
};
// resolvePromise实现
resolvePromise(promise2, x, resolve, reject){
// 如果 newPromise 和 x 指向同⼀对象,以 TypeError 为据因拒绝执⾏ newPromise
// 这里为了防止死循环
if(promise2 === x){
return reject( new TypeError('The promise and the return value are the same'))
}
if(x instanceof MPromise){
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执⾏x,如果执⾏的时候拿到⼀个y,还要继续解析y
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if (typeof x === 'object' || this.isFunction(x)){
// 如果 x 为对象或者函数
if( x===null ){
// null也会被判断为对象
return resolve(x);
}
let then =null;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error){
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error)
}
// 如果 then 是函数
if(this.isFunction(then)){
let called = false;
// 将 x 作为函数的作⽤域 this 调⽤
// 传递两个回调函数作为参数,第⼀个参数叫做 resolvePromise ,第⼆个参数叫做 rejectPromise
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调⽤,则运⾏ resolvePromise
(y) => {
// 需要有⼀个变量called来保证只调⽤⼀次
if(called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调⽤,则以据因 r 拒绝 promise
(r) => {
if(called) return;
called = true;
reject(r);
}
)
} catch (error){
// 如果调用 then 方法就抛出异常 e;
if(called) return;
// 否则以e为据因拒绝promise
reject(error)
}
} else {
// 如果then不是函数,以x 为参数执行promise
resolve(x)
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执⾏ promise
resolve(x)
}
}
// catch 方法
catch (onRejected) {
return this.then(null, onRejected)
}
/******----静态方法******/
static resolve (value){
if(value instanceof MPromise){
return value;
}
return new MPromise((resolve) => {
resolve(value)
})
}
static reject (reason) {
return new MPromise((resolve,reject)=>{
reject(reason)
})
}
}