一步一步教你手写Promise
写这篇文章主要目的是为了巩固自己的知识点以及更深入了解promise的原理,对于初学者有一些不友好,建议初学者先去了解promise基本用法再来看这篇文章。从零开始一步一步教学写then、all、catch、race、Promise.resolve、Promise.reject,原理的话一边写一边给大家介绍,那我们就开始吧!
第一步:初始结构搭建
我们都知道Promise总共有三种状态,分别是pending、fulfilled、reject,三种状态不可逆,通过调用resolve、reject以及抛出错误可以改变状态,只能是pending–>fulfilled或者是pending–>reject,我们throw利用try catch去捕捉错误信息
function Promise(executor){
//添加属性,一开始的状态为pending
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的this值
const self = this;
//resolve 函数
function resolve(data){
// 判断状态(解决状态可逆)若状态不为pending下面代码则无法执行直接return
if(self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'fulfilled';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
}
//reject 函数
function reject(data){
// 判断状态(解决状态可逆)若状态不为pending下面代码则无法执行直接return
if(self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'rejectd';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
}
try{
//同步调用执行器函数,执行resolve和reject
executor(resolve,reject);
}catch(e){
//若抛出错误的话则会变成reject状态
reject(e);
}
}
//给原型添加then方法,这样实例对象可以用then方法
Promise.prototype.then = function(onResolved,onRejected){
}
- 这样一开始的结构差不多就搭建完啦,自己可以去验证一下
第二步:then方法
1.then方法执行回调
Promise.then
要传两个回调函数,一个是当状态为fulfilled的回调函数另一个则为状态为reject状态的回调函数
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult);
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
}
得到的结果如下图所示:
当然这还不是最终版我们还会进行完善,请继续往下看
2.异步任务回调的执行
现在假如有一个场景需要有异步任务回调执行,过几秒才会变状态,这怎么执行呢,所以我们要继续完善我们的代码,使其可以异步任务回调的执行,若在我们刚刚写的代码加入异步任务回调会怎么样呢?
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('123');
}, 1000)
})
p.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
})
答案是:没有输出,没有执行。经过一秒才会去改变状态,所以进入then回调函数的时候
他的一开始状态是处于pending状态而我们的代码没有去判断这个状态的函数
。1.所以我们要去完善并判断当一开始状态是pending的情况。
2.当我们状态还是pending状态时候,我们怎么实现当状态发生改变的时候去执行回调函数呢,状态未发生变化则不能执行回调函数,等状态改变再去调用保存的回调函数, 这时候就用的有点巧妙了,先将
回调函数进行保存
,我们新建一个callback属性用来保存回调函数(+++号表示新增代码)3.4.回调函数保存后,我们该什么时候去调用它呢,我们需要状态改变后去调用
onResolved
、onRejected
函数,则我们找到resolve
,reject
进行编写,我们去判断callback里面是否有回调函数,如果有的话则在状态之后调用函数
function Promise(executor) {
//添加属性,一开始的状态为pending
this.PromiseState = 'pending';
this.PromiseResult = null;
// 声明属性保存回调函数
this.callback = {}; //2.++++++++++++++++
//保存实例对象的this值
const self = this;
//resolve 函数
function resolve(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'fulfilled';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用成功的回调函数 3.++++++++++++
if(self.callback.onResolved){
self.callback.onResolved();
}
}
//reject 函数
function reject(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'rejected';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用失败的回调函数 4.++++++++
if(self.callback.onRejected){
self.callback.onRejected();
}
}
try {
//同步调用执行器函数,执行resolve和reject
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
当然我们的then方法也得进行更新
Promise.prototype.then = function (onResolved, onRejected) {
//成功状态
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult);
}
//失败状态
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
//异步状态处理
if(this.PromiseState === 'pending'){ //1.++++++++++
//保存回调函数
this.callback = {
onResolved, //键值和键名相等简写
onRejected
}
} //+++++++
}
现在打印p进行查看则有callback属性(回调函数)
现在我们的then方法就可以异步任务回调的执行啦,将上面setTimeout内行代码执行在控制台进行查看,过一秒输出结果,如下图所示
==注意!!==
我们等一秒输出结果之后再点开promise对象状态会变成fulfilled,若还未输出结果就点开promise对象则状态还是pending
3.指定多个回调函数
当我们执行下列代码会发生什么呢
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('123');
}, 1000);
})
p.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
})
p.then(value => {
alert(value);
}, reason => {
alert(reason);
})
console.log(p)
用内置的Promise则会先输出123然后再弹出一个alert 123的弹窗,而用我们刚刚自己写的Promise会发生什么呢?答案是只会弹出一个alert 123弹窗,为什么会这样子呢?因为后面的回调函数覆盖了前面console.log的回调所以只有一个弹窗输出,所以我们还要进行代码改进
1。对于回调函数的保存我们要进行改变,声明一个callbacks数组保存回调函数,上一步我们用的是对象进行保存。
2.然后将每个回调函数作为对象push到callbacks这个数组里面
3.此时数组存放多个对象,每个对象则有
onResolved
,onRejected
回调函数,利用forEach遍历数组执行回调函数
function Promise(executor) {
//添加属性,一开始的状态为pending
this.PromiseState = 'pending';
this.PromiseResult = null;
// 声明属性(改用数组的方法) 1.+++++++++
this.callbacks= [];
//保存实例对象的this值
const self = this;
//resolve 函数
function resolve(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'fulfilled';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用成功的回调函数 3.+++++++
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
//reject 函数
function reject(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'rejected';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用失败的回调函数
self.callbacks.forEach(item => { //4.++++++++
item.onRejected(data)
})
}
try {
//同步调用执行器函数,执行resolve和reject
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//给原型添加then方法,这样实例对象可以用then方法
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult);
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
if(this.PromiseState === 'pending'){
this.callbacks.push({ // 2.+++++++
onResolved,
onRejected
})
}
}
4.同步修改状态then方法结果返回
我们都知道调用then后返回的对象是一个promise对象,我们用
内置的Promise
来执行一下下面的结果
let p = new Promise((resolve, reject) => {
resolve('ok');
})
const result = p.then(value => {
console.log(value);
},reason => {
console.log(reason)
})
console.log(result)
结果如下图所示:
用我们上面自己写的Promise则不会返回一个Promise对象,我们继续再来改写一下
1.我们在then方法里面套一个Promise,确保then返回的是一个Promise对象
2.首先我们要明白如果在then里面没有一个返回值也就是没有return,它返回的是一个成功的Promise对象,若then里面又return一个Promise对象则是看里面的Promise是什么状态返回的对象就是什么状态,当我们处于成功状态的时候会执行onResolved回调,失败则会调用onRejected回调
3.首先判断then里面onResolved回调返回的是一个Promise对象的话,则我们可以运行.then方法获取结果,若返回的不是一个Promise的话,则直接去调用resolve方法使状态变为成功
4.若我们在then回调里抛出一个错误,则返回的对象也是一个失败的状态,跟上面捕捉错误方法一样去利用
try catch
Promise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => { //1.++++++++
if (this.PromiseState === 'fulfilled') {
try { //4.++++++++
// 获取回调函数的执行结果
let result = onResolved(this.PromiseResult);
//判断
if (result instanceof Promise) { //2.+++++++
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else { // 3.+++++++
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
//若检测到有抛出错误时则变为失败的状态
reject(e);
}
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved,
onRejected
})
}
})
}
==我们用我们写的Promise运行下面代码==
//当then里面回调返回是一个Promise
let p = new Promise((resolve, reject) => {
resolve('ok');
})
const res = p.then(value => {
return new Promise((resolve,reject) => {
resolve('123333');
})
},reason => {
console.log(reason);
})
console.log(res);
//当then里面回调返回不是一个Promise(无return)
let p1 = new Promise((resolve, reject) => {
resolve('ok');
})
const res1 = p1.then(value => {
console.log(value)
},reason => {
console.log(reason);
})
console.log(res1);
//当then里面抛出一个错误
let p2 = new Promise((resolve, reject) => {
resolve('ok');
})
const res2 = p2.then(value => {
throw 'error';
},reason => {
console.log(reason);
})
console.log(res2);
运行结果如下图所示:
5.异步修改状态then方法结果返回
有人问这步骤刚刚2.2不是已经做过了嘛?答案是:不一样
执行下列代码就知道了
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
})
const res = p.then(value => {
console.log(value)
},reason => {
console.log(reason);
})
console.log(res);
这时候’ok’会经过一秒输出,但是res状态还是处于pending状态并没有发生改变,这是为什么呢?我们在.then方法里面执行回调函数,而我们要根据回调函数去返回res的一个状态,这个意思就是若我们执行onResolved回调的时候我们状态就是成功的并且要返回给Promise对象也是成功的(res)。
1.我们之前在this.PromiseState === ‘pending’时候去直接调用回调这是不可行的,我们稍微做改进变为一个函数,并且把PromiseResult参数传入
2.接下来几步都是和上面一样进行判断啦,判断返回的是否是一个Promise对象,这里就不再重复诉说了
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
if (this.PromiseState === 'fulfilled') {
try {
// 获取回调函数的执行结果
let result = onResolved(this.PromiseResult);
//判断
if (result instanceof Promise) {
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () { //1.++++++++
try { //2.下面和上面内个步骤一样具体可以去看2.4+++++++++++
//执行成功回调函数
let result = onResolved(self.PromiseResult);
// 判断
if (result instanceof Promise) {
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
},
onRejected: function () { //1.++++++++
try { //2.++++++++
onRejected(self.PromiseResult);
let result = onRejected(self.PromiseResult);
// 判断
if (result instanceof Promise) {
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
})
}
})
}
然后我们在运行上面的示范例子的代码可以得到正确的结果,如下图所示:
6.then方法完善和优化
由我们上述图片可知,我们还未对状态为失败的时候进行改进,所以我们也对失败状态进行更改,详细步骤请见
2.4
,若不改进的话若Promise里面调用reject(),则状态还会处于pending状态而不是fulfilled状态
if (this.PromiseState === 'rejected') {
try {
let result = onRejected(this.PromiseResult);
if(result instanceof Promise){
result.then(v => {
resolve(v);
},r => {
reject(r);
})
}else{
resolve(result);
}
} catch (e) {
reject(e);
}
}
细心的小伙伴有没有发现上面这行代码已经复用很多次啦?我们可以封装一个函数去使代码更加的简洁以及维护的更加方便
//封装函数
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(this.PromiseResult);
//判断
if (result instanceof Promise) {
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
接下里贴一下我们then方法已经变得非常简洁明了啦
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
//封装函数
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult); //注意这里面的this指向哦!!记得要更改
//判断
if (result instanceof Promise) {
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'fulfilled') {
callback(onResolved);
}
if (this.PromiseState === 'rejected') {
callback(onRejected);
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
})
}
})
}
!!这样我们的then方法就已经完成啦!!有没有坚持到这里的小伙伴嘛在评论区call个1
第三步:catch方法
接下来我们来封装catch方法,catch方法用来指定失败的回调函数,并且返回结果也是一个Promise对象,这时候我们就可以用到我们已经封装好的then方法
//添加catch方法
Promise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected);
}
- 接下来我们执行这行代码:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 1000);
})
p.then(value => {
console.log(111);
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.log(reason);
})
如果你对Promise有了解的话应该知道上面的代码应该会输出error,没错这个就是catch方法的
异常穿透
,若其中有一部分发生错误的话,则catch会立马接收到这个信息,利用我们上述刚刚写的catch方法会报错,这是为什么呢?答案是:当我们p对象还是pending状态的时候会去进行回调函数的保存,
console.log(111)
这个回调函数返回的是一个pending状态的Promise,且这个回调函数会保存在p这个对象属性上面而且这个失败的回调是一个undefined:因为第二个参数并没有传,状态改完之后会执行reject()函数,则会报错,最简单的来讲失败的原因是因为第二个参数没有传入1.当然我们内置的Promise.then里面是可以少传参数的,所以我们要进行判断then方法回调函数是否有onRejected参数传入
2.我们同样也要对onResolved函数是否传入进行判断,若没有进行判断的话,则就无法进行then方法的
值的传递
,所以我们同样的也要用同样的方法进行判断
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 判断回调函数参数
if (typeof onRejected !== 'function') { //1.+++++++++++
onRejected = reason => {
throw reason;
}
}
if (typeof onResolved !== 'function') { //2.++++++++++
onResolved = value => value;
//value => {return value}
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if (result instanceof Promise) {
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'fulfilled') {
callback(onResolved);
}
if (this.PromiseState === 'rejected') {
callback(onRejected);
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
})
}
})
}
用我们写好的catch方法去执行下来代码的结果为:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('okok');
}, 1000);
})
p.then().then(value => {
console.log(222);
throw 'error';
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
})
!!这样我们的catch方法就完成啦!!是不是很简单(没有啦还挺绕的自己重新再写一遍还是有点困难)
第四步:resolve方法封装
- 我们的resolve方法不属于实例对象上面的方法,而是属于Promise这个函数对象的方法,所以我们添加应该下面这样声明,并且传递value参数,返回一个Promise对象
- 这里我们也要再次判断传入的这个参数是否是一个Promise对象,如果是的话则可以直接调用then方法,不是的话则返回一个Promise对象给它
Promise.resolve = function(value){
// 返回Promise对象
return new Promise((resolve,reject) => {
if(value instanceof Promise){
value.then(v => {
resolve(v);
},r => {
reject(r);
})
} else{
//状态设置为成功
resolve(value);
}
});
}
执行下列代码进行演示:
let p = Promise.resolve('ok');
const p2 = Promise.resolve(new Promise((resolve, reject) => {
resolve('success');
}));
console.log(p);
console.log(p2);
结果为:
!!这样我们的resolve方法就完成啦!!
第五步:reject方法封装
这个方法和resolve相似这里就不再进一步解释啦
//添加reject方法
Promise.reject = function (reason) {
return new Promise((resolve,reject) => {
reject(reason);
});
}
第六步:all方法封装
我们all方法,返回的结果是一个Promise对象,参数通常是传入一个数组,结果由promise这个的数组状态决定,若数组里面的Promise都成功则返回结果是一个成功的状态,以及数组的一个结果,若其中一个失败的话,返回的结果是一个Promise失败的对象且返回的是数组里面失败的Promise的结果
let p1 = new Promise((resolve, reject) => {
resolve('Ok');
})
let p2 = Promise.resolve('Success');
let p3 =Promise.resolve('123');
let result = Promise.all([p1,p2,p3]);
console.log(result)
下列为内置Promise的结果:
返回结果的状态是根据数组里面的Promise去判断的
如何判断都成功呢?
1.所以我们要用到遍历,去遍历传进来的这个数组promises,并且每个对象都可以调用then方法
2.我们需要遍历完数组去判断是否都为成功,遍历完数组才能去调用
resolve
函数,而不是遍历完一个promise[i]就去调用,这样子的话假如第一个成功的话就直接返回了。所以我们需要声明一个变量去计算成功的个数,并且成功状态加1,等遍历完数组进行一个判断:如果这个count的值与传进来的数组长度一样,则代表所有的promise都为成功,再去调用resolve函数返回一个成功的对象3.我们all方法调用完需要有一个数组去保存结果,所以我们在这要声明一个数组去保存结果,若成功的话则会把结果存到数组,所以我们在成功回调编写代码,
我们可以用push方法去保存,但这就有一个瑕疵了,结果的顺序和数组的顺序有可能不相同的,因为先后改变的时间状态不一定
,所以这里就是一个很巧妙的地方,见下列代码!!(很重要!!)arr[i] = v
这行,我们利用元素在数组的下标对数据进行保存4.失败的结果就很简单啦,若有一个promise为失败则直接调用reject就可以返回一个失败的promise了
//添加all方法
Promise.all = function (promises) {
//返回为Promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0; //2.
let arr = [];
//遍历
for (let i = 0; i < promises.length; i++) { //1.
//
promises[i].then(v => {
//得知对象的状态是成功
// resolve(); 不能这么写,需要遍历完数组再去调用该函数
count++; //2.
//将当前promise对象成功的结果 存入到数组中
//arr.push(v); 这种方法会有瑕疵!!看上面分析的原因
arr[i] = v; //很巧妙的地方
//做一个判断
if (count === promises.length) { //2.
resolve(arr);
}
}, r => {
reject(r);
})
}
})
}
!!这样我们的all方法就封装好啦!!可以看下运行结果!
第七步:race封装
我们的race方法呢,传入一个参数也是promise组成的数组,返回结果也是一个Promise对象,而这个对象的状态是由数组里面最先改变状态的promise状态,我们用内置的Promise看一下下面代码运行结果,p1先改变状态所以作为返回结果并且值为ok
let p1 = new Promise((resolve, reject) => {
resolve('Ok');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('123');
let result = Promise.race([p1, p2, p3]);
console.log(result)
实现这个方法同样也是需要遍历数组,race与all方法不一样,不需要遍历完整个数组再去判断是否为成功,谁先运行则直接返回该状态就好了,不知道大家能不能理解。race封装稍微简单一些
//添加race方法
Promise.race = function(promises){
return new Promise((resolve,reject) => {
for(let i = 0; i < promises.length ; i++){
promises[i].then(v => {
//修改返回对象的状态为成功
resolve(v);
},r => {
//修改返回对象的状态为失败
reject(r);
})
}
})
}
- 同样我们来验证自己写的代码是否正确
执行下列代码:
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Ok');
}, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('123');
let result = Promise.race([p1, p2, p3]);
console.log(result)
- 由于p1是经过一秒才改变状态,所以Promise.all返回的应该是p2的结果,我们来看下结果
最后一个步骤了!!!快大功告成
我们都知道Promise.then是一个异步执行任务而且是一个微任务,这可能牵扯到一点eventloop知识了,这里就不详细说eventloop知识啦,来举一个例子,我们用
内置的Promise
来运行下面代码,则控制台会输出111–>333–>222,因为会等同步代码运行完后才会去执行异步代码,用我们自己写的Promise
,控制台则会输出111–>222–>333。
let p1 = new Promise((resolve, reject) => {
resolve('Ok');
console.log('111');
})
p1.then(value => {
console.log('222');
})
console.log(333);
我们需要怎么做才能让我们then是异步执行的呢,我们在then方法里面进行更改,我们在回调函数外面包一个settimeout函数使其变成异步任务(当然底层肯定不是这样实现的啦!!)只用看末尾有++++号的就是新增代码
function Promise(executor) {
//添加属性,一开始的状态为pending
this.PromiseState = 'pending';
this.PromiseResult = null;
// 声明属性
this.callbacks = [];
//保存实例对象的this值
const self = this;
//resolve 函数
function resolve(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'fulfilled';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => { //++++++++
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
//reject 函数
function reject(data) {
// 判断状态(解决状态可逆)
if (self.PromiseState !== 'pending') return
//修改对象状态(promiseState)
self.PromiseState = 'rejected';
//设置对象结果值(promiseResult)
self.PromiseResult = data;
//调用失败的回调函数
setTimeout(() => { //++++++++
self.callbacks.forEach(item => {
item.onRejected(data)
})
});
}
try {
//同步调用执行器函数,执行resolve和reject
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//给原型添加then方法,这样实例对象可以用then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 判断回调函数参数
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
if (typeof onResolved !== 'function') {
onResolved = value => value;
//value => {return value}
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if (result instanceof Promise) {
//如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(() => { //++++++++
callback(onResolved);
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => { //++++++++
callback(onRejected);
});
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
})
}
})
}
总结
本文还蛮长的,整理也整理了好久,当然面试的话通常不会让你手写一个完整的Promise,比较重要的是Promise.all和Promise.race方法这两个比较常考手写题!本人自己虽然写了两三遍Promise题但感觉还是蛮复杂的,要考虑的点蛮多的,所以一定要多敲代码!多敲代码!多敲代码!!重要的事情说三遍!如果喜欢的话可以点赞收藏,本人也是第一次写这么长的总结文章,如果有哪写的不好的地方,请大家谅解!有问题的话可以再评论区提出!后面附上手写Promise的源码放在github上面,有ES5版本的还有ES6用class写的版本