前言
Hello~大家好! 新年伊始,先给大家拜个晚年:祝各位掘友们2024年工作顺利!身体健康!万事如意!!!

回到正题,在前端项目开发中,无论你是刚入门的小白还是"叱咤风云"多年的老鸟,一定都绕不开Promise的使用。
本篇文章对于Promise的介绍和用法就不多赘述了,我们专心来探究Promise内部实现的逻辑,阅读本篇文章的最终目的是能够实现一个自定义的Promise。
还是老样子,阅读前请确保以下几点:
熟练掌握Promise使用语法
有些同学可能不熟悉ES6中class的用法,所以本篇文章我们使用ES5中的函数和原型链来模拟ES6中的class特性
如果同学们对ES5中的原型对象和原型链知识感兴趣的话可以在评论区告诉我,我会找时间更新一篇《搞懂原型对象和原型链》
文章中涉及到this指向的知识,如果你对this指向有疑问或者不熟悉可以先看看我之前的两篇文章:
Promise 使用方法
javascript
let p = new Promise((resolve, reject) => {
resolve("ok");
});
console.log(p);
p.then(
(value) => {
console.log(value);
},
(error) => {
console.log(error);
}
);

我们从Promise最简单的一个使用方法开始,可以看到上面代码和输出结果:
- 通过
new关键字创建了一个Promise类型的实例对象赋值为p - 给
Promise构造函数传入一个回调函数 p实例对象调用了自身的then方法
一、 搭建框架
在这一步里,我们先搭建好基础框架:
-
既然
p实例对象是通过new关键字创造出来的,那么Promise就是一个构造函数。 -
Promise构造函数接收一个参数(回调函数),我们叫它执行器函数:executor。 -
p实例对象可以调用then方法,那就说明Promise的原型对象上有一个then函数,并且接收两个参数,我们命名为onResolved和onRejected。
ini
function MyPromise(executor){
};
MyPromise.prototype.then = function (onResolved,onRejected){
};
好了,第一步就大功告成了,是不是很简单?

后面我们会基于这个搭建出来的"框架"一点一点的去完善实现功能
二、同步调用执行器函数,且需要带上两个参数 reslove/reject
javascript
function MyPromise(executor){
+ // resolve 函数
+ function resolve(data){};
+ // reject 函数
+ function reject(data){}
+ //同步调用执行器函数
+ executor(resolve,reject);
}
MyPromise.prototype.then = function (onResolved,onRejected){
};
-
Promise函数接收到了执行器以后,需要同步调用这个执行器函数executor,并且传入resolve和reject参数 -
那么问题来了,
resolve和reject是什么东东呢? -
回到最开始的使用案例代码里面,我们看到
resolve("ok");reject("faild"); -
resolve和reject其实是更改Promise状态的两个函数,两者同样都是接收一个data参数
三、 实现resolve函数和reject函数
在上一步里面我们仅仅是定义了resolve函数和reject函数,在这一步里我们来实现resolve函数和reject函数的逻辑
1. resolve函数
resolve函数的功能是什么呢?
-
修改状态:在用户使用
resolve函数后,Promise的状态从初始化的pending状态变成fulfilled状态 -
设置结果值:在用户使用
resolve函数后,Promise的结果值变成用户传入的数据。
ini
function MyPromise(executor){
+ this.PromiseState = 'pending';
+ this.PromiseResult = null;
// 保存实例对象的this值
+ const self = this;
// resolve 函数
function resolve(data){
+ // 1.修改对象的状态 (promiseState)
+ self.PromiseState = 'fulfilled';
+ // 2.设置对象结果值(promiseResult)
+ self.PromiseResult = data;
};
// reject 函数
function reject(data){ }
//同步调用执行器函数
executor(resolve,reject);
}
- 需要特别注意的一点:这里的this指向要小心处理。为什么呢?我们还是回到使用案例里面看看:
javascript
let p = new Promise((resolve, reject) => {
resolve("ok");
});
resolve函数是处在箭头函数里面的,这个时候调用resolve函数,this指向是window。 我们期望这个this是指向实例对象p身上,所以需要提前保存this指向。
2. reject函数
reject函数和resolve函数是同样的逻辑,不同的是状态更改为rejected
ini
function MyPromise(executor){
this.PromiseState = 'pending';
this.PromiseResult = null;
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data){
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
};
+ // reject 函数
+ function reject(data){
+ // 1.修改对象的状态 (promiseState)
+ self.PromiseState = 'rejected';
+ // 2.设置对象结果值(promiseResult)
+ self.PromiseResult = data;
+ }
//同步调用执行器函数
executor(resolve,reject);
}
四、 处理抛出异常情况
- 在执行器函数里面,除了通过
resolve和reject函数可以改变Promise的状态。使用throw关键字抛出异常也可以改变状态。我们先看下面的原生Promise例子效果:
javascript
let p = new Promise((resolve, reject) => {
throw "error msg";
});
console.log(p);
p.then(
(value) => {
console.log("res:", value);
},
(error) => {
console.log("error:", error);
}
);

-
可以看到,如果在执行器函数内部中抛出了错误,那么
Promise的状态就会变成rejected,且then函数中就会执行失败的回调函数。问题来了,如何实现这一功能呢? -
其实非常简单,我们使用
try catch语句包裹执行器函数executor,当catch到错误的时候,执行reject函数,将Promise的状态改为失败状态,将error值当成Promise的结果值。
kotlin
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
};
// reject 函数
function reject(data) {
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
}
// 处理异常
+ try {
+ //同步调用执行器函数
+ executor(resolve, reject);
+ } catch (error) {
+ // 修改promise状态为失败
+ reject(e)
+ }
}
五、 promise状态只能改变一次
目前我们自定义的Promise有一个非常大的问题,就是Promise的状态可以多次改变。
javascript
let p = new MyPromise((resolve, reject) => {
reject('error');
resolve('ok');
});
console.log(p);

-
可以看到,
Promise的状态从失败状态 又变成了成功状态 ,这明显是不符合Promise的特点的。 -
所以我们在
resolve函数和reject函数中要加入一个判断限制:-
Promise的状态只能从 pending 变成 fulfilled 状态
-
Promise的状态只能从 pending 变成 rejected 状态
-
kotlin
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
+ if(self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
};
// reject 函数
function reject(data) {
+ if(self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
六、 实现then方法功能
1.执行回调函数
then方法的第一个功能就是根据Promise状态调用不同的回调函数, 且在onResolved方法和onRejected方法中加入参数(PromiseResult)
ini
+ MyPromise.prototype.then = function (onResolved, onRejected) {
+ if(this.PromiseState === 'fulfilled'){
+ onResolved(this.PromiseResult);
+ }
+ if(this.PromiseState === 'rejected'){
+ onRejected(this.PromiseResult);
+ }
+ }
2. 异步任务回调的处理
我们来看一个例子:
javascript
let p = new MyPromise((resolve, reject) => {
setTimeout(function () {
resolve("ok");
}, 1000);
});
console.log(p);
p.then(
(value) => {
console.log("res:", value);
},
(error) => {
console.log("error:", error);
}
);

-
可以看到,
Promise还是pending状态,并且没有执行任何一个回调函数。这是为什么呢? -
如果是在正常同步代码逻辑执行时,
resolve或者reject函数后,状态会改变。接着执行then方法,then方法会根据状态,调用不同的回调函数。 -
但是在异步的时候,计时器1秒钟后才会改变状态,在这1秒钟之前,如果执行了then函数,此时状态是pending,then方法不知道调用哪个回调函数。
-
所以我们在
then方法里面,加入一个pending状态的判断,如果执行then函数时,Promise状态还没改变,就先把这两个回调函数保存起来。 -
等到调用
resolve函数或者reject函数时,再取出来根据状态执行不同的回调函数
kotlin
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
// 保存回调函数
+ this.callback = {};
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 执行成功的回调函数
+ if (self.callback.onResolved) {
+ self.callback.onResolved(data);
+ }
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 执行失败的回调函数
+ if (self.callback.onRejected) {
+ self.callback.onRejected(data);
+ }
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult);
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult);
}
+ if (this.PromiseState === 'pending') {
+ this.callback = {
+ onResolved,
+ onRejected
+ }
+ }
}
七、指定多个回调函数的实现
我们继续看下一个例子,给MyPromise指定多个then函数:
javascript
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok");
}, 1000);
});
console.log(p);
p.then((value) => {
console.log("res1:", value);
});
p.then((value) => {
console.log("res2:", value);
});
p.then((value) => {
console.log("res3:", value);
});
p.then((value) => {
console.log("res4:", value);
});

-
executor中如果是异步操作,这时候指定了多个then函数,那么在第二个then函数执行的时候,第二个then里面的成功回调函数,会覆盖之前的回调函数。 -
同理,第三个
then里面的成功回调函数会覆盖前面第二个then指定的回调函数。以此类推。 -
如何解决这个问题呢?非常简单。只需要将原来
callback对象改为数组即可
kotlin
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
+ this.callbacks = [];
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的回调函数
+ self.callbacks.forEach(item=>{
+ if (item.onResolved) {
+ item.onResolved(data);
+ }
+ })
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的失败函数
+ self.callbacks.forEach(item=>{
+ if (item.onRejected) {
+ item.onRejected(data);
+ }
+ })
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.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({
+ onResolved,
+ onRejected
+ })
+ }
}
八、对then方法的返回结果进行处理
-
then方法是可以有返回值的,且返回值是一个新的Promise类型的实例对象。 -
那么问题来了,这个新的
Promise类型的实例对象的结果值是什么呢? -
答案:结果是由
then函数选择执行哪一个回调函数的结果来决定的。 -
下面我们分为两种情况进行分析:
1. 同步情况
先看下面的例子:
then函数返回值不为Promise类型
javascript
let p = new Promise((resolve, reject) => {
resolve("ok");
});
const result = p.then((value) => {
console.log("res:", value);
// 相当于 return undefined
});
console.log(result)

- 可以看到在执行成功的回调函数以后,
return了一个undefined,此时result是一个新的Promise实例对象,状态为成功且值为undefined
then函数返回值为Promise类型
javascript
let p = new Promise((resolve, reject) => {
resolve("ok");
});
const result = p.then((value) => {
console.log("res:", value);
return new Promise((resolve)=>{
resolve("okok")
})
});

- 可以看到在执行成功的回调函数以后,
return了一个新的Promise对象,此时result是一个新的Promise实例对象,状态为成功值且为'okok'
代码功能完善:
- 首先要修改then方法的返回值: 返回值应该是一个新的
Promise实例对象: (return new Promise()) - 获取回调函数的执行结果:
let result = onResolved(this.PromiseResult); - 判断结果类型:
- 如果是
Promise类型。then方法里面可能有抛出异常,还需要加入try..catch对异常进行处理 - 如果不是
Promise类型,直接将状态变为成功的状态。
- 如果是
ini
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的回调函数
self.callbacks.forEach(item => {
if (item.onResolved) {
item.onResolved(data);
}
})
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的失败函数
self.callbacks.forEach(item => {
if (item.onRejected) {
item.onRejected(data);
}
})
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.PromiseState === 'fulfilled') {
try {
let result = onResolved(this.PromiseResult);
if (result instanceof MyPromise) {
result.then(res => {
resolve(res);
}, err => {
reject(err)
})
} else {
// 结果的对象状态为成功
resolve(result);
}
} catch (error) {
reject(error)
}
}
if (this.PromiseState === 'rejected') {
let result = onRejected(this.PromiseResult);
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved,
onRejected
})
}
})
}
异步情况
异步情况是指在执行器函数中出现了异步代码 ,请看下面原生Promise代码:
javascript
let p = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("ok");
}, 1000)
});
const result = p.then((value) => {
console.log("res:", value);
});
console.log(result)

我们替换成自定义的MyPromise 你会发现并没有满足我们的期望,此时的状态还是pending
javascript
let p = new MyPromise((resolve, reject) => {
setTimeout(()=>{
resolve("ok");
}, 1000)
});
const result = p.then((value) => {
console.log("res:", value);
});
console.log(result)

为了更好的说明原因, 请看下面的图:

- 当计时器执行的时候,此时还没到1秒,
Promise的状态还是pending - 那么在执行
then函数的时候,是不是就进入pending状态的判断逻辑里面。在这段逻辑里面,代码知识往callbacks数组里面添加了回调函数,并没有改变状态。 - 此时
then函数return了一个新的Promise对象给result,那这个result不就是pending状态了吗?
完善代码
知道了原因以后,我们继续对代码进行改造:
-
在
then函数中,如果是pending状态,在push 进callbacks数组时,同时执行这个回调函数 -
获取到这个回调函数的结果
-
对这个结果进行判断是否是
Promise对象类型 -
同样的,我们需要注意this指向的问题
ini
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的回调函数
self.callbacks.forEach(item => {
if (item.onResolved) {
item.onResolved(data);
}
})
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的失败函数
self.callbacks.forEach(item => {
if (item.onRejected) {
item.onRejected(data);
}
})
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
+ const self = this;
return new MyPromise((resolve, reject) => {
if (this.PromiseState === 'fulfilled') {
try {
let result = onResolved(this.PromiseResult);
if (result instanceof MyPromise) {
result.then(res => {
resolve(res);
}, err => {
reject(err)
})
} else {
// 结果的对象状态为成功
resolve(result);
}
} catch (error) {
reject(error)
}
}
if (this.PromiseState === 'rejected') {
let result = onRejected(this.PromiseResult);
}
if (this.PromiseState === 'pending') {
+ this.callbacks.push({
+ onResolved: function () {
+ try {
+ let result = onResolved(self.PromiseResult);
+ if (result instanceof MyPromise) {
+ result.then(res => {
+ resolve(res);
+ }, err => {
+ reject(err)
+ })
+ } else {
+ // 结果的对象状态为成功
+ resolve(result);
+ }
+ } catch (error) {
+ reject(error)
+ }
+
+ },
+ onRejected: function () {
+ try {
+ let result = onRejected(self.PromiseResult);
+ if (result instanceof MyPromise) {
+ result.then(res => {
+ resolve(res);
+ }, err => {
+ reject(err)
+ })
+ } else {
+ // 结果的对象状态为成功
+ resolve(result);
+ }
+ } catch (error) {
+ reject(error)
+ }
+ }
+ })
+ }
+ })
+ }
九、完善then函数rejected状态的处理
-
细心的同学会发现,在then函数里面,我们之前只对
fulfilled状态进行了处理,对rejected状态还没完善逻辑。 -
其实
rejected状态中的逻辑跟fulfilled状态的处理逻辑是相似的,并且在pending状态中,充满了各种冗余相似的代码,如下图所示。所以这一节我们将代码进行一个封装和完善。

javascript
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的回调函数
self.callbacks.forEach(item => {
if (item.onResolved) {
item.onResolved(data);
}
})
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
// 调用成功的失败函数
self.callbacks.forEach(item => {
if (item.onRejected) {
item.onRejected(data);
}
})
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new MyPromise((resolve, reject) => {
// 封装工具函数
+ function callbackUtil(type){
+ try {
+ let result = type(self.PromiseResult);
+ if (result instanceof MyPromise) {
+ result.then(res => {
+ resolve(res);
+ }, err => {
+ reject(err)
+ })
+ } else {
+ // 结果的对象状态为成功
+ resolve(result);
+ }
+ } catch (error) {
+ reject(error)
+ }
+ }
if (this.PromiseState === 'fulfilled') {
+ callbackUtil(onResolved)
}
if (this.PromiseState === 'rejected') {
+ callbackUtil(onRejected)
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
+ onResolved: function () {
+ callbackUtil(onResolved)
},
+ onRejected: function () {
+ callbackUtil(onRejected)
}
})
}
})
}
十、完善catch方法与解决异常穿透问题
catch方法
- catch方法的功能:Promise 对象的 catch () 方法用于注册一个在 promise 被拒绝时调用的函数。
- 官方的定义稍微有点拗口,简单来说就是当
Promise状态称为rejected时,这个catch方法就会执行
继续看一个原生Promise的效果:
javascript
let p = new Promise((resolve, reject) => {
setTimeout(()=>{
reject("error");
}, 1000)
});
p.catch(err => {
console.log(err) // error
})
我们继续完善catch方法:
javascript
+ MyPromise.prototype.catch = function (onRejected) {
+ return this.then(undefined, onRejected);
+ };
异常穿透
先看原生Promise的效果,在then方法中指定回调函数时,是可以允许用户不传入成功或者失败的回调函数。
javascript
let p = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("ok");
}, 1000)
});
p.then(res => {
console.log(res);
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
完善代码
javascript
MyPromise.prototype.then = function (onResolved, onRejected) {
const self = this;
//判断回调函数参数
+ if (typeof onRejected !== "function") {
+ onRejected = (reason) => {
+ throw reason;
+ };
+ }
+ if (typeof onResolved !== "function") {
+ onResolved = (value) => value;
+ }
return new MyPromise((resolve, reject) => {
// 封装函数
function callbackUtil(type){
try {
let result = type(self.PromiseResult);
if (result instanceof MyPromise) {
result.then(res => {
resolve(res);
}, err => {
reject(err)
})
} else {
// 结果的对象状态为成功
resolve(result);
}
} catch (error) {
reject(error)
}
}
if (this.PromiseState === 'fulfilled') {
callbackUtil(onResolved)
}
if (this.PromiseState === 'rejected') {
callbackUtil(onRejected)
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callbackUtil(onResolved)
},
onRejected: function () {
callbackUtil(onRejected)
}
})
}
})
}
十一、实现 Promise.resolve方法
resolve函数返回的是一个新的Promise类型的实例对象resolve函数如果接收的参数是普通数据类型,那么返回的实例对象状态为成功fulfilled状态resolve函数如果接收的参数是Promise类型的实例对象,需要判断是什么状态。- 如果是成功状态,那么
resolve函数返回的实例对象状态为成功fulfilled状态 - 如果是失败状态,那么
resolve函数返回的实例对象状态为成功rejected状态
javascript
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(
(v) => {
resolve(v);
},
(e) => {
reject(e);
}
);
} else {
resolve(value);
}
});
};
十二、实现Promise.reject方法
reject方法永远都是返回失败的Promise实例对象,状态为rejected。
javascript
MyPromise.reject = function (value) {
return new MyPromise((resolve, reject) => {
reject(value);
});
};
十三、实现Promise.all方法
- 当传入一个 Promise 对象的数组时,
Promise.all方法会返回一个新的 Promise。 - 这个新的
Promise在所有输入的Promise都成功(resolve)后才会resolve,并且其结果是一个包含每个输入Promise结果值的数组,顺序与输入数组相同。 - 如果任何一个输入的
Promise被拒绝(reject),那么Promise.all返回的 Promise 会立即 reject,并返回第一个被拒绝的 Promise 的拒绝原因。
ini
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
if (promises.length === 0) return resolve(promises);
let count = 0;
let result = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(v) => {
//只要执行了当前函数,就代表当前promise对象成功了
//条件:必须每个promise对象都成功才能执行resolve
count++;
//将当前promise对象结果存入数组,直接使用push()方法会有小瑕疵,无法固定顺序
result[i] = v;
if (count === promises.length) {
resolve(result);
}
},
(e) => {
reject(e);
}
);
}
});
};
十四、实现 Promise.allsettled 方法
Promise.allSettled同样接受一个可迭代对象,并返回一个新的 Promise 对象。- 返回的 Promise 对象在所有传入的 Promise 都已经解决(无论成功还是失败)后才会被解决。该 Promise 的解决值是一个数组,包含所有传入的 Promise 的结果,每个结果都是一个对象,包含
status字段表示状态("fulfilled" 表示成功,"rejected" 表示失败),以及相应的value或reason字段表示值或拒绝原因。
ini
MyPromise.allSettled = function (promises) {
return new MyPromise((resolve, reject) => {
if (promises.length === 0) return resolve(promises);
let count = 0;
let result = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(v) => {
//只要执行了当前函数,就代表当前promise对象成功了
count++;
//将当前promise对象结果存入数组,直接使用push()方法会有小瑕疵,无法固定顺序
result[i] = v;
if (count === promises.length) {
resolve(result);
}
},
(e) => {
count++;
result[i] = e;
if (count === promises.length) {
resolve(result);
}
}
);
}
});
};
十五、实现 Promise.race方法
- 注意: promise数组中如果有某个promise对象是异步的,需要判断哪个promise对象最先执行
ini
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(v) => {
resolve(v);
},
(e) => {
reject(e);
}
);
}
});
};
十六、完善then方法中的回调函数异步执行情况
什么意思呢?我们用原生的Promise看看效果就清楚了:
javascript
let p = new Promise((resolve, reject) => {
resolve('ok');
console.log(111)
});
p.then(res => {
console.log(222);
})
console.log(333)
// 执行顺序 111->333->222
所以我们在执行回调函数时,也需要进行异步处理,很简单,加上setTimeout包裹一下就能实现
javascript
function MyPromise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
// 保存实例对象的this值
const self = this;
// resolve 函数
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
//异步调用成功的回调函数
+ setTimeout(() => {
+ self.callbacks.forEach((item) => {
+ item.onResolved(data);
+ });
+ });
};
// reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1.修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2.设置对象结果值(promiseResult)
self.PromiseResult = data;
//异步调用失败的回调函数
+ setTimeout(() => {
+ self.callbacks.forEach((item) => {
+ item.onRejected(data);
+ });
});
}
// 处理异常
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (error) {
// 修改promise状态为失败
reject(e)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
const self = this;
//判断回调函数参数
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
if (typeof onResolved !== "function") {
onResolved = (value) => value;
}
return new MyPromise((resolve, reject) => {
// 封装函数
function callbackUtil(type){
try {
let result = type(self.PromiseResult);
if (result instanceof MyPromise) {
result.then(res => {
resolve(res);
}, err => {
reject(err)
})
} else {
// 结果的对象状态为成功
resolve(result);
}
} catch (error) {
reject(error)
}
}
if (this.PromiseState === 'fulfilled') {
+ setTimeout(() => {
+ callback(onResolved);
+ });
}
if (this.PromiseState === 'rejected') {
+ setTimeout(() => {
+ callbackUtil(onRejected)
+ });
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callbackUtil(onResolved)
},
onRejected: function () {
callbackUtil(onRejected)
}
})
}
})
}
结语
-
好了,没骗你们吧!!!
-
十六个步骤以后,我们就已经实现了基础版 的自定义Promise了,为什么说是基础版呢?因为在许多方法实现上我们没有做一些参数数据的校验,在某些判断语句上也有处理比较粗糙的情况出现。
-
用当前这个代码去跑 Promises/A+ 规范的测试用例当然是无法全部通过的。
-
当然这也无伤大雅,最重要的是能够打消同学们对Promise的恐惧 并且能快速搞懂Promise的核心实现原理
-
如果有追求完美的同学可以继续照着 Promises/A+ 规范和使用ES6中的class 来完善我们的自定义Promise
-
最后谢谢大家的观看,如果有帮助到你~希望能得到你的点赞收藏评论!
-
大家也可以移步我的主页,有其他文章供大家阅读:秋天的一阵风
