根据 Promise A+ 规范进行实现,并额外实现其 all 、race 等静态方法。
代码的实现完美符合 Promise A+ 规范
Promise / A+ 规范
所谓规范,也就是我们实现promise时,需要遵循的一些规范(当然你也可以不遵循……)。
那么,规范这种东西我懒得写了,promise A+ 具体规范可以看下面:
- [Promise A+ 规范 - 中文](Promise A+ 规范 (malcolmyu.github.io))
- [Promise A+ 规范 - 中文](Promise/A+规范 - SegmentFault 思否)
- Promise A+ 规范 - 英文
我们的主要任务还是以代码实现为主!
基本结构
通过原生Promise我们可以知道,Promise 它实际上就是一个构造函数,毕竟只有构造函数才可以使用 new ,那么,我们就以ES6语法来进行我们的代码实现。
首先,把我们Promise这个类的骨架给搭建起来
class Promise {
constructor() {
}
}
执行器
Promise接收一个参数,这个参数是一个函数,同时它包含2个形参 resolve 和 reject 。
那么,我们就需要在构造器中接收这个函数。
只要你基础不是很差,应该能看出,resolve 和 reject 是由我们的类进行传递的,也就是说,这2个方法是Promise自己身上的方法
class Promise {
constructor(executor) {
executor(this.resolve, this.reject);
}
resolve = () => {}
reject = () => {}
}
在这里,我们做了几件事:
- 接收executor这个执行函数
- 往类中添加resolve和reject两个方法
- 执行executor并传递我们的resolve和reject给它
实现resolve
用过原生promise的都应该知道,resolve是一个函数,且该函数可以接收一个参数,下面是原生Promise的例子
// 原生Promise
new Promise((resolve, reject) => {
resolve(1); // 这个就是我们要实现的
}).then(value => {
console.log(value); // 只有resolve了,才能进入then这里,而value就是上面resolve的1
});
先不管then,我们先来实现resolve,在实现之前,根据A+规范,我们知道:
promise有三种状态 pending 、fulfilled 、rejected,分别代表等待中,成功,失败。
而在promise中一旦resolve,就会把promise的状态从pending变为 fulfilled。
并且,你 resolve(1) 中的参数 1 我也得接收的对吧?我们就用一个变量 value 来接收。resolve的参数是可选的,你可以传,你传了我就接收,你不传我就默认undefined。
最后,我们要知道,resolve的作用是把promise从pending 状态转为 fulfilled 状态。
const PENDING = 'pending'; // pending等待状态
const FULFILLED = 'fulfilled'; // resolve成功状态
const REJECTED = 'rejected'; // reject失败状态
class Promise {
state = PENDING; // promise的初始状态,也就是默认状态是pending
value = null; // resolve的value
constructor(executor) {
executor(this.resolve, this.reject);
}
resolve = (value) => {
// 只有状态为pending时才可以resolve
if(this.state === PENDING) {
// 修改状态为fulfilled
this.state = FULFILLED;
this.value = value;
}
}
}
实现reject
reject的实现与上面的resolve差不多,区别在于,它是将promise的状态从 pending 状态转为 rejected状态。
同样的,reject也可以接收一个参数,我们就用一个变量 reason 来保存它的参数。
const PENDING = 'pending'; // pending等待状态
const FULFILLED = 'fulfilled'; // resolve成功状态
const REJECTED = 'rejected'; // reject失败状态
class Promise {
state = PENDING; // promise的初始状态,也就是默认状态是pending
value = null; // resolve的value
reason = null; // reject的reason
constructor(executor) {
executor(this.resolve, this.reject);
}
reject = (reason) => {
// 只有状态为pending时才可以resolve
if(this.state === PENDING) {
// 修改状态为fulfilled
this.state = FULFILLED;
this.reason = reason;
}
}
}
测试
写到这里,我们先来进行一个小小的测试,看看我们写的代码是否有误。
new Promise((resolve, reject) => {
console.log('执行我们自己的promise');
})
如果执行上面的代码后能正常输出console的内容,则证明无误。
我们接着往下写。
实现then(重点难点)
在实现之前,我们应该知道几个点:
- then什么时候会被触发
- then有多少个形参
- 假如then有返回值怎么办
我们先来回答上面的三个问题
// 原生Promise
new Promise((resolve, reject) => {
console.log(1);
resolve(2);
}).then(value => {
console.log(value);
return 3;
}, err => {
console.log(err);
}).then(value => {
console.log(value);
})
观察上面的代码,我们知道
- 只有在Promise被实例化的同时,执行了resolve,才会触发then
- then有2个形参,分别对应成功(fulfilled)和失败(rejected)两种状态的回调函数
- then里的返回值会作为下一个then成功状态的回调函数参数
最后,我们还得知道,在 A+ 规范中规定了,then的两个形参名字应为:
- onFulfilled:promise状态成功时,参数为当前状态值value或者没有。
- onRejected:promise状态为失败时,参数是失败信息reason或者没有。
基本形态
then方法本质上就是我们Promise类上的一个方法,它接收2个形参,就这样。
class Promise {
/*
......
......
*/
then = (onFulfilled, onReject) => {
}
}
onFulfilled
onFulfilled是干嘛的呢?它是,当我们promise当前的状态为成功时,会调用的函数。
它有一个参数value,就是我们 resolve(value) 中的 value。
// then中的onFulfilled实现
then = (onFulfilled, onReject) => {
// 只有当前状态为成功fulfilled时才执行
if(this.state === FULFILLED) {
// 执行onFulfilled并把我们的value传递给它
onFulfilled(this.value);
}
}
onReject
onReject与onFulfilled差不多,区别在于,只有当我们promise的状态为失败时,才会调用。
它有一个参数,就是我们 reject(reason) 中的 reason。
// then中的onReject实现
then = (onFulfilled, onReject) => {
// 只有当前状态为成功rejected时才执行
if(this.state === REJECTED) {
// 执行onReject并把我们的reason传递给它
onReject(this.reason);
}
}
测试
那么,我们来测试一波
// 我们的promise
new Promise((resolve, reject) => {
console.log('value', 1);
resolve(2);
}).then(value => {
console.log('value', value);
});
// 执行结果
// value 1
// value 2
观察执行结果,能看出,我们的代码是 完美 实现。
但是,假如我们的promise里涉及到异步操作呢?
// 我们的promise
new Promise((resolve, reject) => {
console.log('value', 1);
// 模拟异步代码,假设我们正在发送ajax请求
setTimeout(() => {
resolve(2);
}, 0);
}).then(value => {
console.log('value', value);
});
// 执行结果
// value 1
why! 为什么?我们的 value 哪去了?
其实是这样的,我们的 setTimeout 是异步代码,因此会被延迟执行,哪怕你写的时间是 0。
随后,js把你的异步代码给丢到一边玩泥巴后,又往后看了看还有没有别的代码,它发现了 then 。
由于我们此刻的then是同步代码,所以它就先执行then了,把then的事情干完了,才去执行我们的setTimeout。
你想想,我then都执行完了,你还resolve有毛用?
异步处理
通过上面的解释说明,我们知道了, 由于then先执行的缘故,导致我们的resolve变得没有了意义,那么我们的解决方案是什么呢?
首先,我们知道,promise的初始状态都是pending,且只有 resolve 和 reject 可以修改状态。
那么,我 resolve 都还没有执行,此时promise的状态不就是 pending 了嘛,所以呀,我们只需要 在then里处理pending状态 就可以了。
class Promise {
// ....
onFulfilledCallback = null; // 成功时执行的函数
onRejectedCallback = null; // 失败时执行的函数
// then中的onFulfilled实现
then = (onFulfilled, onReject) => {
// 只有当前状态为成功pending时才执行
if(this.state === PENDING) {
// 保存成功时的处理函数
this.onFulfilledCallback = onFulfilled;
// 保存失败时的处理函数
this.onRejectedCallback = onReject;
}
}
}
上面是在 then 中增加了对pending状态的判断,以及增加了2个类属性。
接下来,我们还得再做一件事,我们上面把成功和失败的处理函数保存起来了,那么应该在什么时候,又在哪调用呢?
答案是:resolve 和 reject
resolve = () => {
resolve = (value) => {
// 只有状态为pending时才可以resolve
if (this.state === PENDING) {
// ....
// 调用resolve修改状态为成功时,执行成功的处理函数
this.onFulfilledCallback && this.onFulfilledCallback(value);
}
}
reject = (reason) => {
// 只有状态为pending时才可以reject
if (this.state === PENDING) {
// ....
// 调用reject修改状态为失败时,执行失败的处理函数
this.onRejectedCallback && this.onRejectedCallback(reason);
}
}
}
测试
再次进行异步代码测试
// 我们的promise
new Promise((resolve, reject) => {
console.log('value', 1);
// 模拟异步代码,假设我们正在发送ajax请求
setTimeout(() => {
resolve(2);
}, 1500);
}).then(value => {
console.log('value', value);
});
// 执行结果
// value 1
// value 2
可以看到,我们定时器设置了1.5秒,在输出 value 1的时候,等待了1.5秒,随后输出 value 2。
那么,我们的异步处理就搞定了。
到这里,我们的代码就已经开始复杂起来了,不过问题不大,假如你们感觉理解起来还有点晕,先不要往下看,先把上面的知识理清楚,多写多思考几遍就会了。
链式调用
我们先来看原生的promise链式调用例子
new Promise((resolve, reject) => {
resolve(1);
}).then().then().then().then().....
可以看到,可以无限制的往下点出then。
而我们的呢,结果竟是……
// 我们的promise
new Promise((resolve, reject) => resolve(1))
.then(value => {
console.log('value', value);
})
.then(value => { // 到这里就报错了,说then是undefined
console.log('value', value);
});
// TypeError: Cannot read property 'then' of undefined
在做这个需求之前,我们先捋一捋,先思考个问题,什么东西可以使用 then ?
**答:**Promise实例对象
因为then本来就是promise类的方法,只有promise的实例对象才拥有 then
那么,如何才能做到链式调用 then 呢?
**答:**then 每次被调用时,都返回一个Promise的实例对象。
那么我们来实现一下
then = (onFulfilled, onReject) => {
// 把我们之前的代码全部放到这个promise2中
let promise2 = new Promise((resolve, reject) => {
// 只有当前状态为成功fulfilled时才执行
if (this.state === FULFILLED) {
// 执行onFulfilled并把我们的value传递给它
onFulfilled(this.value);
}
// 只有当前状态为成功rejected时才执行
if (this.state === REJECTED) {
// 执行onReject并把我们的reason传递给它
onReject(this.reason);
}
// 只有当前状态为成功pending时才执行
if (this.state === PENDING) {
// 保存成功时的处理函数
this.onFulfilledCallback = onFulfilled;
// 保存失败时的处理函数
this.onRejectedCallback = onReject;
}
});
// 最后返回这个promise2实例对象
return promise2;
}
再次执行上一轮的测试,会发现,虽然不报错了,但是,我的 第二个 then 似乎没有被执行?
我们把代码改造一下:
class Promise {
// ....
onFulfilledCallback = []; // 成功时执行的函数
onRejectedCallback = []; // 失败时执行的函数
// ...
resolve = (value) => {
// 只有状态为pending时才可以resolve
if (this.state === PENDING) {
// ....
// 调用resolve修改状态为成功时,执行成功的处理函数
while (this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()();
}
}
}
reject = (reason) => {
// 只有状态为pending时才可以resolve
if (this.state === PENDING) {
// ....
// 调用reject修改状态为失败时,执行失败的处理函数
while (this.onRejectedCallback.length) {
this.onRejectedCallback.shift()();
}
}
}
// then中的onFulfilled实现
then = (onFulfilled, onReject) => {
// 返回一个Promise实例,实现链式调用的功能
let promise2 = new Promise((resolve, reject) => {
// 成功的处理函数
const onFulfilledCallback = () => {
// 执行onFulfilled并把我们的value传递给它
setTimeout(() => {
// 得到resolve或reject的返回值,将其赋值给变量x
const x = onFulfilled(this.value);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
})
}
// 失败的处理函数
const onRejectedCallback = () => {
// 执行onReject并把我们的reason传递给它
setTimeout(() => {
// 得到resolve或reject的返回值,将其赋值给变量x
const x = onReject(this.reason);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
})
}
// 只有当前状态为成功fulfilled时才执行
if (this.state === FULFILLED) {
// 执行成功处理函数
onFulfilledCallback();
}
// 只有当前状态为成功rejected时才执行
if (this.state === REJECTED) {
// 执行失败处理函数
onRejectedCallback();
}
// 只有当前状态为成功pending时才执行
if (this.state === PENDING) {
// 保存成功时的处理函数
this.onFulfilledCallback.push(onFulfilledCallback);
// 保存失败时的处理函数
this.onRejectedCallback.push(onRejectedCallback);
}
});
return promise2;
}
// 处理then的返回值
resolvePromise = (promise2, x, resolve, reject) => {
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
} else {
resolve(x);
}
}
}
那么,上面这一大串代码,我们做了什么呢?
- 保存成功和失败状态处理函数的变量 改为数组
- resolve和reject在最后均通过循环遍历我们的状态处理函数数组,依次取出并执行。
- 把成功处理函数和失败处理函数单独封装,并将其放入定时器内执行。
- 增加了 resolvePromise 这个类方法
为什么要这么做?
每当我们点一次 then,then函数都会被执行,且then的成功和失败处理函数我们也需要处理。
promise.then().then().then().then().then()...
这个代码会触发5次 then 方法
而且,上一个 then 的返回值
是下一个 then 的 resolve 参数
我们也说过了,只有promise调用了resolve的时候,才能进入then
那我们是不是返回了一个promise2 ?
你返回了一个promise实例对象,可如果你这个实例对象不调用resolve,我能进入下一个 then吗?
不能!
那么怎么判断 then 有没有返回值呢?简单,onFulfilled 和 onRejected 就对应着 then 的2个方法,我可以用个 x 变量来接收。
接收到then的返回值后(如果没有主动return,就是undefined)
我又增加了一个类方法 resolvePromise 来判断,本次then执行结束,应该调用 resolve,还是调用 reject。
在 resolvePromise 中,根据promise A+ 规范,我们需要根据 x 的数据类型,进行不同的操作。
resolve = (promise2, x, resolve, reject) => {
// 如果x是对象或者函数
if(x !== null && (typeof x === 'object' || typeof x === 'function'))) {
} else {
// 来到这里,代表x是一个普通值类型,直接使用resolve把x给带走
resolve(x);
}
}
那为什么我要在定时器里写呢?
因为我们的promise2在执行到fulfilled和rejected的时候,promise2这个变量还没有初始化完毕呢,因此,我们使用定时器,把它推入事件队列中,等到下一轮事件循环的时候,就能拿到初始化后的promise2了。
then = (onFulfilled, onReject) => {
let promise2 = new Promise((resolve, reject) => {
if(this.state === FULFILLED) {
// 得到resolve或reject的返回值
const x = onFulfilled(this.value);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
// TypeError报错,提示promise2在使用前还没有初始化……
}
});
return promise2;
}
说白了就是这个阶段如果不用定时器来延迟执行时机的话,我们无法拿到promsie2,因为此时的promise2还没有完成初始化,它还是一个 不存在的变量,所以我们需要使用定时器。
到了这时候,我们的promise链式调用功能就完成了。
还是那句话,这一节有点小难,也有点绕,如果没有理解,建议先把这块内容理清楚!
完善resolvePromise
resolvePromise的作用是用于处理then里的返回值,假如你的返回值是普通值、对象、函数,我要怎么处理。
我们需要遵循 promise A+ 规范来实现!
来看下我们当前的代码
resolvePromise = (promise2, x, resolve, reject) => {
// 如果x是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
} else {
// 能进入这里,代表x是一个普通值
resolve(x);
}
}
根据 A+ 规范,如果x是对象或者函数,需要声明一个变量then,然后把x.then赋值给它,假如x身上没有then这个属性,则reject这个错误
resolvePromise = (promise2, x, resolve, reject) => {
// 如果x是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 声明一个变量then
let then;
try {
// 取出x.then并赋值给then(假如x被设置了不可读,则可能会报错,所以需要try/catch)
then = x.then;
} catch (err) {
// 失败,reject
reject(err);
}
} else {
// 能进入这里,代表x是一个普通值
resolve(x);
}
}
接下来,我们需要 判断这个变量then是不是一个函数
如果then是一个函数,则
- 修改then的this指向为x
- 传递2个参数(这2个参数其实就是对应then方法的两个形参)
y: 相当于 then 的resolve方法,被调用时执行 resolvePromiser: 相当于 then 的reject方法- 如果
y和r都被调用了,或者被调用了多次,则只第一次有效,后面的忽略。 - 如果在调用
then时抛出了异常,则:- 如果
y或r已经被调用了,则忽略它。 - 否则, 以
e为reason将promise拒绝。
- 如果
如果then不是函数,则
- 以x为值,调用resolve
代码实现
// 如果x是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 声明一个变量then
let then;
// 声明一个变量called,代表y或r是否被调用过
let called = false; // false代表没有被调用过
try {
// 取出x.then并赋值给then(假如x被设置了不可读,则可能会报错,所以需要try/catch)
then = x.then;
} catch (err) {
// 失败,reject
reject(err);
}
// 判断then是否是一个函数
if (typeof then === 'function') {
try {
// 修改then的this指向为x
then.call(
x,
y => {
// 如果y或x已经被调用过,则直接退出
if (called) return;
// 修改called为已调用
called = true;
// 再次执行resolvePromise
this.resolvePromise(promise2, y, resolve, reject);
},
r => {
// 如果y或x已经被调用过,则直接退出
if (called) return;
// 修改called为已调用
called = true;
// reject这个r
reject(r);
}
)
} catch (e) {
// 如果then在被调用的过程中出错,则会进入这里,直接reject
reject(e);
}
} else {
// 如果then不是一个函数,则以x进行resolve
resolve(x);
}
} else {
// x不是对象,也不是函数,则以x进行resolve
resolve(x);
}
到此为止,我们的resolvePromise方法就完成了
异常处理
为了避免代码执行过程中出现错误,进而导致程序崩溃,我们需要在可能会出现错误的地方进行容错处理
**成功处理函数增加 try/catch **
// 成功的处理函数
const onFulfilledCallback = () => {
// 执行onFulfilled并把我们的value传递给它
setTimeout(() => {
try {
// 得到resolve的返回值
const x = onFulfilled(this.value);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
})
}
失败处理函数增加 try/catch
// 失败的处理函数
const onRejectedCallback = () => {
// 执行onReject并把我们的reason传递给它
setTimeout(() => {
try {
// 得到reject的返回值
const x = onReject(this.reason);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
})
}
增加catch方法
在原生promise的实例对象中是有catch这么一个方法的,它一般写在链式调用的最后面,看个例子
new Promise((resolve, reject) => {
resolve(1);
})
.then(value => {
return Promise.reject('这是一个错误信息');
})
.catch(err => {
console.log('err', err);
})
假如then里没有对错误进行捕获处理,则错误信息会被最后的catch给捕获。
我们来实现一下,实现代码也比较简单
catch = (onRejected) => {
// 其实就是调用then方法,然后只传递reject的处理方法
return this.then(null, onRejected);
}
其它
then方法的两个参数是可选的,可以传,也可以不传。
我们也来实现一下,使得它们变为可选参数。
注意:遵循promise A+ 规范
then = (onFulfilled, onRejected) => {
// 如果onFulfilled不是一个函数,则给它一个默认函数
if (typeof onFulfilled !== 'function') onFulfilled = value => value;
// 如果onRejected不是一个函数,则给它一个默认函数,行为是抛出reason错误信息
if (typeof onRejected !== 'function') onRejected = reason => { throw reason };
}
不理解为什么这么做的同孩,需要多看几遍,多分析几遍
到此为止,我们的promise就已经实现完了
我们可以看到,promise的实现中,then方法是最复杂的
但其实,只要你多看几遍,会发现其实也没有想象中那么难
实现静态resolve
我们来看下原生promise的例子
new Promise((resolve, reject) => {
resolve(1);
}).then(value => {
return Promise.resolve(2);
}).then(value => {
console.log(value); // 2
})
我们可以看到,上面这个例子中的 resolve 是一个静态方法,返回的是一个成功状态的promise,这样我们才可以继续向后点出then。
那么,我们来实现一下,实现过程还是很简单的。
static resolve = (value) => {
return new Promise((resolve, reject) => {
resolve(value);
})
}
对,你没看错,就是这么简单。
接收到用户传递的参数,随后创建一个promise对象,调用该实例对象的resolve(value) 出去,perfect!
实现静态reject
既然有静态resolve,那自然也有静态reject。
实现的过程与静态resolve几乎一样。
static reject = (reason) => {
return new Promise((resolve, reject) => {
reject(reason);
})
}
实现静态all
我们看个原生的例子
let promises = [...];
Promise
.all(promises)
.then(value => {
console.log(value);
})
不了解Promise.all的同学,请自行去百度,这里不会细讲。
promise.all方法通常用来实现并发,例如并发请求等。
同时,它的特性是:所有promise的状态都为成功,才是成功,只要有一个promise是失败的,则整体全部失败。
我们来实现一下
static all = (promises) => {
let result = [];
let count = 0;
// 判断参数是否是一个数组,如果不是数组,则不执行,直接返回该参数
if (!Array.isArray(promises)) return promises;
return new Promise((resolve, reject) => {
// 往result里添加数据
const insertData = (data, index) => {
result[index] = data;
count++;
// 判断是否执行完毕
if(count === result.length) {
resolve(result);
}
}
// 使用循环遍历所有promise并执行
for(let i = 0; i < promises.length; i++) {
promises[i].then(value => insertData(value, i), reject);
}
})
}
实现静态race
race与all特性差不多,区别在于:
只要有一个promise的状态是成功,整体就是整个,只有所有promise都是失败时,才是失败。
实现代码
static race = (promises) => {
if (!Array.isArray(promises)) return promises;
return new Promise((resolve, reject) => {
for(let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
})
}
A+规范测试
我们的promise已经全部实现完了,那么,我们来测试下我们的代码,是否符合promise A+ 规范吧
为了进行代码测试,我们需要往我们的Promise类中增加一个静态方法(它只用来做测试,测完可以删除)
// 全部复制,啥也不用改
static deferred = function () {
let result = {};
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
接下来,把我们写的Promise类给导出(commonJS规范)
module.exports = Promise;
最后,执行测试,在我们文件所在的目录下,打开命令行工具,输入以下命令
npx promises-aplus-tests .\xxx.js
其中的 xxx.js 就是你的文件名,就是我们写的这个Promise文件
我测试了一下,所有代码全部通过了测试,舒服~
完整代码
const PENDING = 'pending'; // pending等待状态
const FULFILLED = 'fulfilled'; // resolve成功状态
const REJECTED = 'rejected'; // reject失败状态
class Promise {
state = PENDING; // promise的初始状态,也就是默认状态是pending
value = null; // resolve的value
reason = null; // reject的reason
onFulfilledCallback = []; // 成功时执行的函数
onRejectedCallback = []; // 失败时执行的函数
constructor(executor) {
executor(this.resolve, this.reject);
}
resolve = (value) => {
// 只有状态为pending时才可以resolve
if (this.state === PENDING) {
// 修改状态为fulfilled
this.state = FULFILLED;
this.value = value;
// 调用resolve修改状态为成功时,执行成功的处理函数
while (this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()();
}
}
}
reject = (reason) => {
// 只有状态为pending时才可以resolve
if (this.state === PENDING) {
// 修改状态为rejected
this.state = REJECTED;
this.reason = reason;
// 调用reject修改状态为失败时,执行失败的处理函数
while (this.onRejectedCallback.length) {
this.onRejectedCallback.shift()();
}
}
}
then = (onFulfilled, onRejected) => {
// 如果onFulfilled不是一个函数,则给它一个默认函数
if (typeof onFulfilled !== 'function') onFulfilled = value => value;
// 如果onRejected不是一个函数,则给它一个默认函数,行为是抛出reason错误信息
if (typeof onRejected !== 'function') onRejected = reason => { throw reason };
let promise2 = new Promise((resolve, reject) => {
// 成功的处理函数
const onFulfilledCallback = () => {
// 执行onFulfilled并把我们的value传递给它
setTimeout(() => {
try {
// 得到resolve的返回值
const x = onFulfilled(this.value);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
})
}
// 失败的处理函数
const onRejectedCallback = () => {
// 执行onRejected并把我们的reason传递给它
setTimeout(() => {
try {
// 得到reject的返回值
const x = onRejected(this.reason);
// 根据返回值类型的不同,进行不同的操作
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
})
}
// 只有当前状态为成功fulfilled时才执行
if (this.state === FULFILLED) {
onFulfilledCallback();
}
// 只有当前状态为成功rejected时才执行
if (this.state === REJECTED) {
onRejectedCallback();
}
// 只有当前状态为成功pending时才执行
if (this.state === PENDING) {
// 保存成功时的处理函数
this.onFulfilledCallback.push(onFulfilledCallback);
// 保存失败时的处理函数
this.onRejectedCallback.push(onRejectedCallback);
}
});
return promise2;
}
resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) reject(new TypeError(`循环引用错误`));
// 如果x是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 声明一个变量then
let then;
// 声明一个变量called,代表y或r是否被调用过
let called = false; // false代表没有被调用过
try {
// 取出x.then并赋值给then(假如x被设置了不可读,则可能会报错,所以需要try/catch)
then = x.then;
} catch (err) {
// 失败,reject
reject(err);
}
// 判断then是否是一个函数
if (typeof then === 'function') {
try {
// 修改then的this指向为x
then.call(
x,
y => {
// 如果y或x已经被调用过,则直接退出
if (called) return;
// 修改called为已调用
called = true;
// 再次执行resolvePromise
this.resolvePromise(promise2, y, resolve, reject);
},
r => {
// 如果y或x已经被调用过,则直接退出
if (called) return;
// 修改called为已调用
called = true;
// reject这个r
reject(r);
}
)
} catch (e) {
// 如果y或x已经被调用过,则直接退出
if (called) return;
// 如果then在被调用的过程中出错,则会进入这里,直接reject
reject(e);
}
} else {
// 如果then不是一个函数,则以x进行resolve
resolve(x);
}
} else {
// x不是对象,也不是函数,则以x进行resolve
resolve(x);
}
}
static resolve = (value) => {
return new Promise((resolve, reject) => {
resolve(value);
})
}
static reject = (reason) => {
return new Promise((resolve, reject) => {
reject(reason);
})
}
static all = (promises) => {
let result = [];
let count = 0;
// 判断参数是否是一个数组,如果不是数组,则不执行,直接返回该参数
if (!Array.isArray(promises)) return promises;
return new Promise((resolve, reject) => {
// 往result里添加数据
const insertData = (data, index) => {
result[index] = data;
count++;
// 判断是否执行完毕
if (count === result.length) {
resolve(result);
}
}
// 使用循环遍历所有promise并执行
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => insertData(value, i), reject);
}
})
}
static race = (promises) => {
if (!Array.isArray(promises)) return promises;
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
})
}
}