Promise的大概功能
- then 接收两个参数,参数1是成功的回调,参数2是失败的回调
- catch 接收一个参数,失败的回调
- finally 接收一个参数,成功/失败都会触发
- resolve 接收一个参数
- reject 接收一个参数
- all 接收一个数组 全部成功或一个失败则结束
- race 接收一个数组 一个完成则结束
- any 接收一个有length可遍历的数据,当里面有一个成功则结束,如果一个成功都没有则报错
- allSettled 接收一个有length可遍历的数据,当里面全部完成则结束,错误不会停止
Promise规范
Promise本质是一个状态机,且状态只能为以下三种:Pending(等待态)
、Fulfilled(执行态)
、Rejected(拒绝态)
,状态的变更是单向的,只能从Pending -> Fulfilled 或 Pending -> Rejected,状态变更不可逆
class IPromise<T> {
// IPromise的状态,等待中,成功,失败
status: 'pending' | 'fulfilled' | 'rejected';
// 存储resolve的队列
resolveQueue: Array<((value?: T) => any)>;
// 存储reject的队列
rejectQueue: Array<((reason: any) => any)>;
// 给then/catch的数据
_value: T | undefined;
// 接收一个函数参数,两个入参是resolve 和 reject
constructor(executor: (reslove: (value: T) => void, reject: (reason: unknown) => void) => void) {
this.resolveQueue = [];
this.rejectQueue = [];
this.status = 'pending';
this._value = undefined;
// 定义一个this,否则resolve/reject不是箭头函数拿不到this
let _this = this;
// 定义resolve
let _resolve = function (_props?: T) {
// 只有状态是pending才可以进行
if (_this.status !== 'pending') return;
// 改变状态
_this.status = 'fulfilled';
// 存储数据
_this._value = _props;
// 判断是否有成功的回调
while (_this.resolveQueue?.length) {
const callback = _this.resolveQueue.shift();
callback?.(_props);
}
};
// 定义reject
let _reject = function (_props: any) {
if (_this.status !== 'pending') return;
_this.status = 'rejected';
_this._value = _props;
while (_this.rejectQueue?.length) {
const callback = _this.rejectQueue.shift();
callback?.(_props);
}
};
// 调用入参 传入resolve和reject
try {
executor(_resolve, _reject);
} catch (error) {
// 如果错误直接执行reject
_reject(error);
}
}
/**
* @then 传入两个参数
*/
then(resolveFn, rejectFn) {
// 给成功队列添加回调
this.resolveQueue.push(resolveFn);
// 给失败队列添加回调
typeof rejectFn === 'function' && this.rejectQueue.push(rejectFn);
}
}
到这里就完成了一个最基础的Promise,但是这里我们还不可以链式调用,并且只能处理异步,当Promise是同步时目前是处理不了的,js执行机制从上到下,Promise里面如果是同步,成功和失败的队列则为空,我们的Promise的回调没有再return一个Promise出去所以不能链式,接下来继续完善一下
then的链式调用和处理同步
要想链式调用则需要Promise的then再return一个Promise出去才可以实现,想要处理同步则需要在then里面判断一下当前状态,现在我们继续修改then的代码
/**
* @then { then传入两个参数,参数1是成功的回调,参数2是失败的 }
*/
then(resolveFn?: (value: T) => any, rejectFn?: (reason: any) => any) {
// 判断参数是否为函数,如果不是函数会把IPromise的数据返回出去
typeof resolveFn === 'function' ? null : resolveFn = value => value;
typeof rejectFn === 'function' ? null : rejectFn = value => value;
/**
* @返回一个IPromise链式调用
*/
return new IPromise((resolve, reject) => {
/**
* @给then的参数包装的执行一下判断返回值是否为IPromise
*/
const fulfilledFn = (value) => {
const res = resolveFn?.(value);
res instanceof IPromise ? res?.then(resolve, reject) : resolve(res);
}
const rejectedFn = (error) => {
const res = rejectFn?.(error);
res instanceof IPromise ? res.then(resolve, reject) : reject(res);
}
// 判断IPromise的状态
switch (this.status) {
case 'pending':
// Promise内部是异步,这里为等待中则给队列中添加任务
this.resolveQueue.push(fulfilledFn);
this.rejectQueue.push(rejectedFn);
break;
case 'fulfilled':
// 如果Promise内部是同步完成则这里直接调用then里面的成功回调
fulfilledFn(this._value);
break;
case 'rejected':
// 如果Promise内部是同步完成并且then的失败回调为function则直接调用
rejectedFn(this._value);
break;
default:
break;
}
})
}
现在我们的Promise就可以处理同步与异步,并且可以链式调用了,接下来我们再完成.catch的部分
.catch 失败回调
完成了then方法,其他catch方法就非常简单,因为then的第二个参数也是失败的回调,我们在这里只需调用的return一个then就好了
catch(rejectFn) {
return this.then(undefined, rejectFn);
}
接下来继续完成.finally的部分
.finally 全部的回调
.finally 不管Promise是成功还是失败都会触发,并且finally拿不到成功/错误的信息,并且finally内部如果return了一个Promise,这个Promise是成功的状态则下一个then拿到的当前Promise的值,如果是失败的状态,则下一个then的失败回调拿到的是finally里面这个Promise的reject值
如下图
了解了finally的功能我们继续往下写
finally(callback) {
const fun = (value) => {
// finally传入的是否为函数
const res = typeof callback === 'function' && callback?.();
// 如果finally的回调返回一个IPromise则根据这个IPromise的状态给值,
if (res instanceof IPromise) {
return res?.status === 'fulfilled' ? value : res?.value;
} else {
// 如果finally回调返回的不是IPromise,则判断当前IPromise的状态为失败则后续的也是失败,否则为成功
return this.status === 'rejected' ? Promise.reject(value) : value;
}
};
// 调用then传入一个成功一个失败
return this.then(
(value) => fun(value),
// promise<200>
(error) => fun(error),
)
}
finally只要Promise完成就会触发,所以这里咱们需要给then里面添加两个回调
这里我们包装一下finally的回调,因为finally的回调拿不到值所以直接直接调用,如果该回调返回了一个Promise,判断该Promise的状态,如果是成功则把当前Promise的值返回给下一个Promise,否则把回调的Promise值给下一个,当回调非函数或者没有返回Promise时则判断当前promise的状态,如果是失败则返回一个失败,这里用到了Promise.reject,快速返回一个失败的Promise,后续我们会补上该方法
.resolve 快速的返回一个Promise
当.resolve的值为Promise时,该Promise一个为失败则失败
static resolve(value) {
// 如果参数为Promise则直接返回这个Promise
if (value instanceof IPromise) return value
// 如果参数飞Promise则创建一个Promise并且参数当值调用成功
return new IPromise(_resolve => _resolve(value));
};
.reject 返回一个失败的Promise
static reject(value) {
// reject不去管参数的是什么类型,直接返回一个失败的Promise
return new IPromise((resolve, reject) => reject(value));
};
.all 当数组里所有参数都执行完成触发/失败一个也触发
all接收一个数组,当数组里面全部完成则结果then的回调拿到一个数组
当里面有一个失败则走到失败回调
static all(callbackArr: IPromise<any>[]) {
// 记录有几个完成
let resultIndex = 0;
// 记录对应下标的结果
let result = [] as any[];
return new IPromise((resolve, reject) => {
// 如果参数不是数组直接报错
if (callbackArr instanceof Array) {
callbackArr?.some((item, index) => {
// 如果不是Promise则直接添加结果
if (item instanceof IPromise) {
item
.then(res => {
result[index] = res; // 给对应下标添加结果
resultIndex++; // 完成数++
// 判断完成数量是否等于总数
if (resultIndex === callbackArr?.length) {
return resolve(result);
}
}, err => {
return reject(err);
})
} else {
result[index] = item;
resultIndex++;
if (resultIndex === callbackArr?.length) {
return resolve(result);
}
}
})
} else {
reject(`TypeError: ${typeof callbackArr} ${callbackArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
}
})
}
.race 竞速,有一个完成则结束
race接收一个数组,当数组里面有一个完成则结束,返回完成的结果
static race(callbackArr: IPromise<any>[]) {
return new IPromise((resolve, reject) => {
// 如果参数不是数组直接报错
if (callbackArr instanceof Array) {
callbackArr?.some((item, index) => {
// 如果不是Promise则直接添加结果
if (item instanceof IPromise) {
item
.then(res => {
return resolve(res);
}, err => {
return reject(err);
})
} else {
return resolve(item);
}
})
} else {
reject(`TypeError: ${typeof callbackArr} ${callbackArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
}
})
}
代码上只需要把all的那些结果总数,结果数组去掉,一个完成直接结束调该Promise
2023 - 03 - 09 补充 start
.any 任意一个成功则结束,race是任意一个完成则结束
入参是一个有length可遍历的类型,所以这里使用for循环,如果循环项非Promise/Promise.then则直接resolve,如果没有一个resolve则会自动到reject
用then接收,如果是成功则return 该值,否则return一个Promise的错误
/**
* @any 任意一个成功则返回
*/
static any(promiseArr) {
if (typeof promiseArr.length === 'number') {
return new IPromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
if (promiseArr[i] instanceof IPromise) {
promiseArr[i]
.then(res => {
return resolve(res);
})
} else {
// 如果当前值不是Promise则直接成功
return resolve(promiseArr[i]);
}
}
})
// 拿到当前Promise的回调,如果走then则代表完成直接把值抛出去
.then(res => {
return res;
}, () => {
// 如果catch则代表所有的promise都是rejected
return Promise.reject('AggregateError: All promises were rejected');
})
} else {
return IPromise.reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
}
}
.allSettled 所有的完成则结束,all是所有的成功/有一个失败则结束
入参是一个有length可遍历的类型,所以这里使用for循环,如果循环项非Promise/Promise.then则给result添加对应下标添加数据,rindex++,判断是否为最后一个
/**
* @allSettled 当数组里的promise全部执行完成返回结果,中途报错不会影响结果
*/
static allSettled(promiseArr: IPromise<any>[]) {
// 有几个已执行
let rindex = 0;
// promise对应的结果
let result = [] as any[];
// return一个Promise
return new IPromise((resolve, reject) => {
// 封装一个方法,参数1是结果,参数2是当前下标,参数3可选的一个状态,默认为fulfilled成功
function pushRes(value, index, type?: 'rejected') {
result[index] = {
type: type || 'fulfilled',
value: value
};
rindex++;
// 判断当前是否全部执行完成
if (rindex === promiseArr?.length) {
resolve(result);
}
};
if (typeof promiseArr.length === 'number') {
for (let i = 0; i < promiseArr.length; i++) {
if (promiseArr[i] instanceof IPromise) {
promiseArr[i]
.then(res => {
pushRes(res, i);
}, err => {
pushRes(err, i, 'rejected');
})
} else {
pushRes(promiseArr[i], i);
}
}
} else {
reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
}
})
}
2023 - 03 - 09 补充 end
到这里我们的Promise就完成了,下面我上一下全量代码
class IPromise<T> {
// IPromise的状态,等待中,成功,失败
status: 'pending' | 'fulfilled' | 'rejected';
// 存储resolve的函数
resolveQueue: Array<((value?: T) => any)>;
// 存储reject的函数
rejectQueue: Array<((reason: any) => any)>;
// 给then/catch的数据
_value: T | undefined;
// 接收一个函数参数,两个入参是resolve 和 reject
constructor(executor: (reslove: (value: T) => void, reject: (reason: unknown) => void) => void) {
this.resolveQueue = [];
this.rejectQueue = [];
this.status = 'pending';
this._value = undefined;
// 定义一个this,否则resolve等不是箭头函数拿不到this
let _this = this;
// 定义resolve
let _resolve = function (_props?: T) {
if (_this.status !== 'pending') return;
_this.status = 'fulfilled';
_this._value = _props;
while (_this.resolveQueue?.length) {
const callback = _this.resolveQueue.shift();
callback?.(_props);
}
};
// 定义reject
let _reject = function (_props: any) {
if (_this.status !== 'pending') return;
_this.status = 'rejected';
_this._value = _props;
while (_this.rejectQueue?.length) {
const callback = _this.rejectQueue.shift();
callback?.(_props);
}
};
// 调用入参
try {
executor(_resolve, _reject);
} catch (error) {
// 如果错误直接执行reject
_reject(error);
}
}
/**
* @then { then传入两个参数,参数1是成功的回调,参数2是失败的 }
*/
then(resolveFn?: (value: T) => any, rejectFn?: (reason: any) => any) {
// 判断参数是否为函数,如果不是函数会把IPromise的数据返回出去
typeof resolveFn === 'function' ? null : resolveFn = value => value;
typeof rejectFn === 'function' ? null : rejectFn = value => value;
/**
* @返回一个IPromise链式调用
*/
return new IPromise((resolve, reject) => {
/**
* @给then的参数包装的执行一下判断返回值是否为IPromise
*/
const fulfilledFn = (value) => {
const res = resolveFn?.(value);
res instanceof IPromise ? res?.then(resolve, reject) : resolve(res);
}
const rejectedFn = (error) => {
const res = rejectFn?.(error);
res instanceof IPromise ? res.then(resolve, reject) : reject(res);
}
// 判断IPromise的状态
switch (this.status) {
case 'pending':
// Promise内部是异步,这里为等待中则给队列中添加任务
this.resolveQueue.push(fulfilledFn);
this.rejectQueue.push(rejectedFn);
break;
case 'fulfilled':
// 如果Promise内部是同步完成则这里直接调用then里面的成功回调
fulfilledFn(this._value);
break;
case 'rejected':
// 如果Promise内部是同步完成并且then的失败回调为function则直接调用
rejectedFn(this._value);
break;
default:
break;
}
})
}
/**
* @catch { 错误的回调 }
*/
catch(rejectFn) {
/**
* @直接调用then传入一个undefined和一个catch的回调
*/
return this.then(undefined, rejectFn);
}
/**
* @finally { 回调不管成功还是错误 }
*/
finally(callback?: any) {
const fun = (value) => {
const res = typeof callback === 'function' && callback?.();
// 如果finally的回调返回一个IPromise则根据这个IPromise的状态给值,
if (res instanceof IPromise) {
return res?.status === 'fulfilled' ? value : res?._value;
} else {
// 如果finally回调返回的不是IPromise,则判断当前IPromise的状态为失败则后续的也是失败,否则为成功
return this.status === 'rejected' ? IPromise.reject(value) : value;
}
};
// 调用then传入一个成功一个失败
return this.then(
(value) => fun(value),
// promise<200>
(error) => fun(error),
)
}
/**
* @resolve 返回一个IPromise实例
* */
static resolve<R>(value?: R | IPromise<R>): IPromise<R> {
// resolve传入一个参数,返回一个promise,如果该参数为promise则直接返回
if (value instanceof IPromise) return value;
return new IPromise((resolve) => resolve(value as R));
};
/**
* @reject 返回一个失败的IPromise实例
* */
// IPromise.reject();
static reject<R>(value: R): IPromise<R> {
// reject传入一个参数,返回promise,不管参数的类型
return new IPromise((resolve, reject) => reject(value));
};
/**
* @all 当数组里的promise全部执行完成或者有一个报错则结束
*/
static all(promiseArr: IPromise<any>[]) {
// 有几个已执行
let rindex = 0;
// promise对应的结果
let result = [] as any[];
// return一个Promise
return new IPromise((resolve, reject) => {
// 如果入参不是数组则直接reject报错
if (promiseArr instanceof Array) {
promiseArr?.forEach((item, index) => {
// 如果不是Promise则直接给对应位置添加返回值
if (item instanceof IPromise) {
item
.then(res => {
result[index] = res;
rindex++;
// 判断当前是否全部执行完成
if (rindex === promiseArr?.length) {
resolve(result);
}
}, err => {
reject(err);
})
} else {
result[index] = item;
rindex++;
if (rindex === promiseArr?.length) {
resolve(result);
}
}
})
} else {
reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
}
})
}
/**
* @race 当数组里的promise有一个完成则结束
*/
static race(promiseArr: IPromise<any>[]) {
return new IPromise((resolve, reject) => {
// 如果入参不是数组则直接reject报错
if (promiseArr instanceof Array) {
promiseArr?.some((item, index) => {
// 如果不是Promise则直接给对应位置添加返回值
if (item instanceof IPromise) {
item
.then(res => {
return resolve(res);
}, err => {
return reject(err);
})
} else {
return resolve(item);
}
})
} else {
reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
}
})
}
/**
* @any 任意一个成功则返回
*/
static any(promiseArr) {
if (typeof promiseArr.length === 'number') {
return new IPromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
if (promiseArr[i] instanceof IPromise) {
promiseArr[i]
.then(res => {
return resolve(res);
})
} else {
// 如果当前值不是Promise则直接成功
return resolve(promiseArr[i]);
}
}
})
// 拿到当前Promise的回调,如果走then则代表完成直接把值抛出去
.then(res => {
return res;
}, () => {
// 如果catch则代表所有的promise都是rejected
return Promise.reject('AggregateError: All promises were rejected');
})
} else {
return IPromise.reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
}
}
/**
* @allSettled 当数组里的promise全部执行完成返回结果,中途报错不会影响结果
*/
static allSettled(promiseArr: IPromise<any>[]) {
// 有几个已执行
let rindex = 0;
// promise对应的结果
let result = [] as any[];
// return一个Promise
return new IPromise((resolve, reject) => {
// 封装一个方法,参数1是结果,参数2是当前下标,参数3可选的一个状态,默认为fulfilled成功
function pushRes(value, index, type?: 'rejected') {
result[index] = {
type: type || 'fulfilled',
value: value
};
rindex++;
// 判断当前是否全部执行完成
if (rindex === promiseArr?.length) {
resolve(result);
}
};
if (typeof promiseArr.length === 'number') {
for (let i = 0; i < promiseArr.length; i++) {
if (promiseArr[i] instanceof IPromise) {
promiseArr[i]
.then(res => {
pushRes(res, i);
}, err => {
pushRes(err, i, 'rejected');
})
} else {
pushRes(promiseArr[i], i);
}
}
} else {
reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
}
})
}
}