- 作者:老汪软件技巧
- 发表时间:2024-08-29 17:02
- 浏览量:
前言
上一章我们了解了如何实现Promise的核心功能,其内部其实主要就是控制Promise的状态,和使用api对其变成异步任务,并且通过内部返回Promise实现了then的链式调用,并且处理了重复调用,这几章节我们就把Promise的实例方法和静态方法做一下实现
catch
catch是Promise上的一个实例方法,主要是用来捕获错误的,再Promise内抛出错误或者是reject都可以被捕获到,这个其实咱们之前已经实现过了,就是then的第二个参数接收的函数。回忆一下,then内呢首先判断传入的是不是函数,不是函数的话则变为函数,进行抛出错误。所有我们只需要再catch函数内直接调用then方法,第一个传入undefined,第二个传入catch接收到的函数就可以,
const P = new MyPromise((resolve, reject) => {
reject('error')
// throw 'throw-error'
})
catch (onRejected) {
return this.then(undefined, onRejected)
}
如果是在内部直接做的抛出错误也需要在catch内进行接收,那么我们可以在函数执行的时候进行捕获错误,然后执行reject
try {
fun(resolve, reject)
} catch (err) {
reject(err)
}
这样就实现了catch做错误捕获,不管是直接抛出的错误还是reject传出的都可以再catch内捕获到
finally
finally方法内和上面的catch其实是一样的,只是finally是不管成功或者失败都会进行执行的,那么我们就可以再内部调用then两个参数都传入finally接收到的函数,那么不管是什么状态,都会执行传入的函数
finally (OnFinally) {
return this.then(OnFinally, OnFinally)
}
这样不管我们是成功或者失败状态都可以调用到OnFinally函数
resolve
resolve呢是Promise上的一个静态方法。resolve静态方法将给定的值转换为一个Promise,所有这里分为两种情况,一种是直接传入了一个Promise我们直接返回就可以,另一种呢是传入了一个值,我们只需要再创建一个Promise且把状态转为fulfilled再进行返回
static resolve (value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise((resolve) => {
resolve(value)
})
}
这样就实现了resolve静态方法,主要就是判断是否为Promise,如果是的话直接俄进行返回,不是的话则创造一个Promise修改为fulfilled状态进行返回
reject
reject和上面其实是一样的,他是不管传入什么,都返回一个rejected状态的Promise对象,所有这里我们就不需要进行判断了,直接拿到传入的值,返回一个Promise对象就可以了
static reject (value) {
return new MyPromise((resolve, reject) => {
reject(value)
})
}
race
race方法呢是接收一个Promise数组,然后返回一个Promise,返回的Promise呢第一个执行完毕的状态敲定,也就是把第一个执行完成的Promise返回,不管是成功还是失败
static race (arr) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject(new TypeError('Argument is not an iterable'));
}
arr.forEach(p => {
MyPromise.resolve(p).then(res => { resolve(res) }, rej => { reject(rej) });
})
});
}
这里返回一个Promise我们需要先判断他是否是一个数组,不是的话则抛出一个错误,是的话就遍历执行,但是传入的每一项可能有的不是Promise,所有我们需要使用resolve方法把他转为一个Promise,然后执行。
all
all呢也是接收一个可迭代的数组,然后返回一个Promise,但是需要考虑的东西比较多,首先如果不是数组的话我们抛出一个错误,如果为空数组的话则直接resolve出去一个空数组就可以,正常的话就是等待所有任务执行完毕后resolve出去,如果有报错的话则是直接返回这个报错结果
static all (arr) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject(new TypeError('Argument is not an iterable'));
}
arr.length === 0 && resolve([])
const results = []
let count = 0
arr.forEach((p, index) => {
MyPromise.resolve(p).then(res => {
results[index] = res
count++
count === arr.length && resolve(results)
}, err => {
reject(err)
})
})
});
}
首先呢我们判断是他是否是一个数组,如果是的话再判断数组的长度,如果长度为0直接返出去一个空数组就可以。如果是一个正常数组,那么我也声明一个数组用来装执行完成的结果,这里用index是为了保证传入的promise数组顺序和执行结果顺序一致,然后再用一个累加器来判断是否执行完成了所有结果,完成了的话就把结果返出去
allSettled
allSettled的方法呢和all是有点类似的,也是接受一个可迭代的promise数组,等到所有的promise都敲定以后返回一个被敲定的promise并带有描述每个 promise 结果的对象数组。也就是不管成功还是失败都是等到执行完成以后把所有的结果进行携带出去
static allSettled(arr) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject(new TypeError("Argument is not an iterable"));
}
arr.length === 0 && resolve([]);
const results = [];
let count = 0;
arr.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => {
results[index] = { status: FULFILLED, value: res };
count++;
count === arr.length && resolve(results);
},
(err) => {
results[index] = { status: REJECTED, reason: err };
count++;
count === arr.length && resolve(results);
}
);
});
});
}
这样就实现了allSettled这个方法,和上面all的实现方式其实基本上是一样的。只不过这个是等到所有的都敲定以后把所有的结果和状态都反出去
any
any函数呢是和all反着来的,它接受一个promise数组,如果是空数组则是抛出错误,且返回的为第一个执行成功的或者是所有都执行失败的结果。
static any(arr) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject(new TypeError("Argument is not an iterable"));
}
arr.length === 0 &&
reject(new AggregateError(arr, "All promises were rejected"));
const error = [];
let count = 0;
arr.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
error[index] = err;
count++;
count === error.length &&
reject(
new AggregateError(error, "All promises were rejected")
);
}
);
});
});
}
如果有一个执行成功则直接返回执行成功的,要不就是都执行失败,把失败的原因数组返回出去
结尾
以上就是promise的所有实例方法了,通过手写以上方法我们可以了解到pormise的实例方法内部是如何运行的,对于后面工作使用和面试来说都有所帮助