前言
上一章我们了解了如何实现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
的实例方法内部是如何运行的,对于后面工作使用和面试来说都有所帮助