实现目标
- 基础功能——then函数异步回调(不带链式调用功能)
- 基础功能——链式调用功能
- 基础功能——catch、finally函数功能
- 高级功能——Promise.resolve、Promise.reject
- 高级功能——Promise.all、Promise.race、Promise.allSettled
- 完整代码示例,并执行case与标准Promise比较
Promise的基本说明
Promise
对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象一个
Promise
有以下几种状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的
then
方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
基础功能
Promise基本构造
/**
*@Promise的三种状态枚举
*/
enum PromiseState {
pending,
fulfilled,
rejected
}
// Promise构造函数传入的执行器类型
type PromiseExecutor<T, E> = (resolve: PromiseResolve<T>, reject: PromiseReject<E>) => unknown;
type PromiseResolve<T> = (value?: T) => void;
type PromiseReject<T> = (error?: T) => void;
//Promise then函数onFulfilled参数类型
type PromiseThenOnFulfilled<T> = (value: T) => Promise | unknown;
//Promise then函数onRejected参数类型
type PromiseThenOnRejected<T> = (error: T) => Promise | unknown;
//Promise catch函数onExcepted参数类型
type PromiseCatchOnExcepted<T> = (error: T) => Promise | unknown;
type PromiseOnFinal = () => unknown;
export class Promise<T = unknown, E = unknown> {
public readonly name = Symbol('Promise');
// 标识当前实例的状态,初始化为pending
private state: PromiseState = PromiseState.pending;
// 成功后数据的存储
private value!: T;
// 失败或异常后数据的存储
private error!: E;
// then成功回调参数的存储
private onFulfilled?: PromiseThenOnFulfilled<T>;
// then失败回调参数的存储
private onRejected?: PromiseThenOnRejected<E>;
// catch函数参数的存储
private onExcepted?: PromiseCatchOnExcepted<E>;
// finally函数参数的存储
private onFinal?: PromiseOnFinal;
// nextPromise, 表明当then\catch\finally函数被调用后,返回的一个新的Promise实例。实现链式调用
private nextPromise?: Promise;
// 构造函数
constructor(executor: PromiseExecutor<T, E> = () => { }) {
}
// then函数,当实例状态变更为fulfilled时,第一个函数参数被回调,当状态变更为rejected时,第二个函数参数被回调。如果一个参数都没有传入,状态会被派生至下次回调函数的出现。
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
}
// catch函数,当实例状态变更为rejected并且then函数没有传入第二个参数时,此函数中传入的参数将被回调。
public catch(onExcepted?: PromiseCatchOnExcepted<E>) {
}
// finally函数,当实例状态变更为成功后失败后,该函数中传入的回调参数都会被调用。
public finally(onFinal?: PromiseOnFinal) {
}
}
then函数异步回调
1.Promise函数被创建时,传入的回调函数即会被调用,所以有如下代码
//some code...
// 实例初始化时即调用
constructor(executor: PromiseExecutor<T, E> = () => { }) {
executor(this.resolve, this.reject)
}
// resolve被调用时,将值保存到实例中,并且更改状态为fulfilled
private resolve = (value?: T) => {
this.value = value as T;
this.setState(PromiseState.fulfilled);
}
// reject被调用时,将值保存到实例中,并且更改状态为rejected
private reject = (error?: E) => {
this.error = error as E;
this.setState(PromiseState.rejected);
}
// 统一状态设置入口,以便状态被改变时做一些事情
private setState = (state: PromiseState) => {
this.state = state;
}
//some code...
- then函数被调用时,将传入的函数保存到实例中,以便状态变更后回调
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
}
- 当状态被变更,触发传入的回调函数,修改之前的setState函数(暂不处理then函数传不传参的情况)
private setState = (state: PromiseState) => {
this.state = state;
if (state === PromiseState.fulfilled) {
this.onFulfilled(this.value);
}
else if (state === PromiseState.rejected) {
this.onRejected(this.error);
}
}
链式回调功能实现
要实现链式回调功能,方法函数必须返回一个同类型的实例。并且,由于Promise的特性,下一个then等函数中回调函数的调用时机,也要根据当前实例then等函数返回的状态而决定。所以才有了第一段代码中nextPromise属性存在的意义。当then等函数被调用时,返回准备好的下一个新的Promise实例,此实例的状态是初始状态,当当前实例的onFulfilled/onRejected/onExcepted被调用后,可以知道其返回值是否为Promise,从而判断该如何将当前状态托管到下一个Promise。
- 改造then函数,使其返回一个新的Promise实例
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
// 返回一个新的Promise实例,下一个then或其他方法的调用,将会在此实例上进行
return this.next();
}
private next() {
// 返回前检查下nextPromise是否被有值
this.checkNextPromise();
return this.nextPromise as Promise;
}
private checkNextPromise(np: Promise | undefined = undefined): np is Promise {
// 一旦发现nextPromise还没有值,就给他赋一个新的Promise实例上去
if (!this.nextPromise) {
this.nextPromise = new Promise(); // 没有传入任何参数的Promise的状态是会处于pending中的
}
return true;
}
- 改造setState,在状态被设置的时候,调用相应的回调函数,并且根据回调函数的返回值类型来设置nextPromise
private resolve = (value?: T) => {
this.value = value as T;
// 将调用setState函数的时机改为异步调用
setTimeout(this.setState, 0, PromiseState.fulfilled);
}
private reject = (error?: E) => {
this.error = error as E;
// 将调用setState函数的时机改为异步调用
setTimeout(this.setState, 0, PromiseState.rejected);
}
private setState = (state: PromiseState) => {
const { nextPromise } = this;
// 理论上是不会存在nextPromise没有值的,因为setState函数的调用一定在nextPromise被初始化之后
if (!nextPromise) {
return;
}
this.state = state;
if (state === PromiseState.fulfilled) {
this.handleFulfilled(nextPromise);
}
}
private handleFulfilled(next: Promise) {
if (this.onFulfilled) {
// 如果有onFulfilled回调,则直接回调其函数,并且检查返回值是否是Promise
this.checkCallResult(this.onFulfilled(this.value), next);
}
else {
// 如果没有,则将成功状态托管给下一个Promise,等待数据被取用
next.resolve(this.value);
}
}
private checkCallResult(result: Promise | unknown, next: Promise) {
if (result instanceof Promise) {
// 如果返回值是Promise实例,则将生成的新Promise代理到返回的Promise上
Promise.transmit(result, next);
}
else {
next.resolve();
}
}
/** @static */
public static transmit(from: Promise, to: Promise) {
from.resolve = to.resolve;
from.reject = to.reject;
}
完善基础功能,实现catch、finally函数
catch函数的回调是在当实例状态变更为失败的时候并且then函数没有传入第二个值时才会被调用。调用后同then函数一样,链式传递。
finally函数的回调是在当实例状态非pending时,在最后始终会调用的一个回调。调用后同then函数一样,链式传递。
constructor(executor: PromiseExecutor<T, E> = () => { }) {
// Promise标准中,executor如果发生异常,也算作是rejected,所以需要捕获异常来达到目的
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
public catch(onExcepted?: PromiseCatchOnExcepted<E>) {
this.onExcepted = onExcepted;
return this.next();
}
public finally(onFinal?: PromiseOnFinal) {
this.onFinal = onFinal;
return this.next();
}
private setState = (state: PromiseState) => {
const { nextPromise } = this;
if (!nextPromise) {
return;
}
this.state = state;
// 不论是reject被调用还是直接发生throw,失败的回调函数都会被调用
try {
if (state === PromiseState.fulfilled) {
this.handleFulfilled(nextPromise);
}
else if (state === PromiseState.rejected) {
this.handleError(nextPromise);
}
} catch (error) {
this.error = error;
this.handleError(nextPromise);
}
}
private handleError(next: Promise) {
if (this.onRejected) {
this.checkCallResult(this.onRejected(this.error), next);
}
else if (this.onExcepted) {
this.checkCallResult(this.onExcepted(this.error), next);
}
else if (this.onFinal) {
this.onFinal();
next.reject(this.error);
}
else {
next.reject(this.error);
}
}
resolve和reject功能的实现
public static resolve<V>(value?: V | Promise) {
// 传入参数如果是Promise,则直接返回,如果是其他,则返回一个新的Promise,并且回调实例的resolve
return value instanceof Promise ? value : new Promise((r) => r(value))
}
public static reject<R>(reason?: R) {
return new Promise((r, j) => {
j(reason)
})
}
Promise.all、Promise.race、Promise.allSettled功能实现
public static allSettled<R, E = R>(iterable: Promise<R, E>[]) {
let complates: Array<R | E> = [];
let completedNumber = 0;
const result = new Promise();
iterable.forEach((p, i) => {
p.then(d => {
complates[i] = d;
completedNumber++;
if (completedNumber === iterable.length) {
result.resolve(complates);
}
}, e => {
complates[i] = e;
completedNumber++;
if (completedNumber === iterable.length) {
result.resolve(complates);
}
});
})
return result as Promise<Array<R | E>, E>;
}
public static all<R, E>(iterable: Promise<R, E>[] | Promise<R, E> | string) {
let succs: R[] = [];
let completedNumber = 0;
const result = new Promise();
const resolve = () => result.resolve(succs);
const reject = (reason: E) => result.reject(reason);
if (iterable instanceof Promise) {
iterable.then(d => {
succs.push(d)
resolve();
}, e => reject(e));
}
else if (typeof iterable === 'string') {
succs = iterable.split('') as any[];
setTimeout(() => resolve());
}
else if (iterable instanceof Array) {
iterable.forEach((p, i) => {
p.then(d => {
completedNumber++;
succs[i] = d;
if (completedNumber === iterable.length) {
resolve();
}
}, e => reject(e));
})
}
return result as Promise<R[], E>;
}
public static race<T, E>(iterable: Promise[]) {
const result = new Promise();
iterable.forEach(item => {
item.then(d => result.state === PromiseState.pending && result.resolve(d), e => result.state === PromiseState.pending && result.reject(e))
})
return result as Promise<T, E>;
}
完整代码
enum PromiseState {
pending,
fulfilled,
rejected
}
type PromiseExecutor<T, E> = (resolve: PromiseResolve<T>, reject: PromiseReject<E>) => unknown;
type PromiseResolve<T> = (value?: T) => void;
type PromiseReject<T> = (error?: T) => void;
type PromiseThenOnFulfilled<T> = (value: T) => Promise | unknown;
type PromiseThenOnRejected<T> = (error: T) => Promise | unknown;
type PromiseCatchOnExcepted<T> = (error: T) => Promise | unknown;
type PromiseOnFinal = () => unknown;
export class Promise<T = unknown, E = unknown> {
public readonly name = Symbol('Promise');
private state: PromiseState = PromiseState.pending;
private value!: T;
private error!: E;
private onFulfilled?: PromiseThenOnFulfilled<T>;
private onRejected?: PromiseThenOnRejected<E>;
private onExcepted?: PromiseCatchOnExcepted<E>;
private onFinal?: PromiseOnFinal;
private nextPromise?: Promise;
constructor(executor: PromiseExecutor<T, E> = () => { }) {
this.handleExecutor(executor);
}
private handleExecutor(executor: PromiseExecutor<T, E>) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
private handleFulfilled(next: Promise) {
if (this.onFulfilled) {
this.checkCallResult(this.onFulfilled(this.value), next);
}
else if (this.onFinal) {
this.onFinal();
next.resolve(this.value);
}
else {
next.resolve(this.value);
}
}
private handleError(next: Promise) {
if (this.onRejected) {
this.checkCallResult(this.onRejected(this.error), next);
}
else if (this.onExcepted) {
this.checkCallResult(this.onExcepted(this.error), next);
}
else if (this.onFinal) {
this.onFinal();
next.reject(this.error);
}
else {
next.reject(this.error);
}
}
private setState = (state: PromiseState) => {
const { nextPromise } = this;
if (!nextPromise) {
return;
}
this.state = state;
try {
if (state === PromiseState.fulfilled) {
this.handleFulfilled(nextPromise);
}
else if (state === PromiseState.rejected) {
this.handleError(nextPromise);
}
} catch (error) {
this.error = error;
this.handleError(nextPromise);
}
}
private checkCallResult(result: Promise | unknown, next: Promise) {
if (result instanceof Promise) {
Promise.transmit(result, next);
}
else {
next.resolve();
}
}
private resolve = (value?: T) => {
this.value = value as T;
setTimeout(this.setState, 0, PromiseState.fulfilled);
}
private reject = (error?: E) => {
this.error = error as E;
setTimeout(this.setState, 0, PromiseState.rejected);
}
private next() {
this.checkNextPromise();
return this.nextPromise as Promise;
}
private checkNextPromise(np: Promise | undefined = undefined): np is Promise {
if (!this.nextPromise) {
this.nextPromise = new Promise(() => { });
}
return true;
}
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
return this.next();
}
public catch(onExcepted?: PromiseCatchOnExcepted<E>) {
this.onExcepted = onExcepted;
return this.next();
}
public finally(onFinal?: PromiseOnFinal) {
this.onFinal = onFinal;
return this.next();
}
/** @static */
public static transmit(from: Promise, to: Promise) {
from.resolve = to.resolve;
from.reject = to.reject;
}
public static resolve<V>(value?: V | Promise) {
return value instanceof Promise ? value : new Promise((r) => r(value))
}
public static reject<R>(reason?: R) {
return new Promise((r, j) => {
j(reason)
})
}
public static allSettled<R, E = R>(iterable: Promise<R, E>[]) {
let complates: Array<R | E> = [];
let completedNumber = 0;
const result = new Promise();
iterable.forEach((p, i) => {
p.then(d => {
complates[i] = d;
completedNumber++;
if (completedNumber === iterable.length) {
result.resolve(complates);
}
}, e => {
complates[i] = e;
completedNumber++;
if (completedNumber === iterable.length) {
result.resolve(complates);
}
});
})
return result as Promise<Array<R | E>, E>;
}
public static all<R, E>(iterable: Promise<R, E>[] | Promise<R, E> | string) {
let succs: R[] = [];
let completedNumber = 0;
const result = new Promise();
const resolve = () => result.resolve(succs);
const reject = (reason: E) => result.reject(reason);
if (iterable instanceof Promise) {
iterable.then(d => {
succs.push(d)
resolve();
}, e => reject(e));
}
else if (typeof iterable === 'string') {
succs = iterable.split('') as any[];
setTimeout(() => resolve());
}
else if (iterable instanceof Array) {
iterable.forEach((p, i) => {
p.then(d => {
completedNumber++;
succs[i] = d;
if (completedNumber === iterable.length) {
resolve();
}
}, e => reject(e));
})
}
return result as Promise<R[], E>;
}
public static race<T, E>(iterable: Promise[]) {
const result = new Promise();
iterable.forEach(item => {
item.then(d => result.state === PromiseState.pending && result.resolve(d), e => result.state === PromiseState.pending && result.reject(e))
})
return result as Promise<T, E>;
}
}
/** case */
// new Promise((resolve, reject) => {
// console.log('start')
// // resolve(1)
// setTimeout(() => {
// resolve(123)
// }, 1000)
// }).then((data) => {
// console.log(data)
// return new Promise((r) => setTimeout(() => r(2), 2000))
// }).then((data) => {
// console.log(data)
// }).then(() => {
// console.log(22222)
// return new Promise((r) => r('eeeeee'))
// }).then().then((data) => {
// console.log(data)
// console.log('end')
// })
// new Promise((resolve, reject) => {
// setTimeout(() => resolve(1), 1000);
// // reject(1)
// }).then((data) => {
// console.log(data)
// return new Promise((r) => {
// setTimeout(() => r(1.1), 1000)
// })
// }).finally(() => {
// console.log('finally')
// console.log(123)
// }).then((data) => {
// console.log('then')
// console.log(data);
// }).catch((e) => {
// console.log('catch')
// console.log(e);
// }).then((data) => {
// console.log('then: last')
// console.log(data)
// })
// new Promise((resolve, reject) => {
// // setTimeout(() => resolve(1), 1000);
// setTimeout(() => reject(2), 1000);
// }).then((data) => {
// console.log(data)
// }).catch((e) => {
// console.log(e)
// return new Promise((r, j) => {
// setTimeout(() => j('e.1'), 1000);
// })
// }).finally(() => {
// console.log('finally')
// }).then((data) => {
// console.log('then')
// console.log(data);
// }).catch((e) => {
// console.log('catch')
// console.log(e);
// }).catch((e) => {
// console.log(e)
// }).then((data) => {
// console.log(data)
// })
// new Promise((resolve, reject) => {
// setTimeout(() => {
// if (Date.now() % 2 === 0) {
// resolve(1);
// }
// else {
// reject(2);
// }
// }, 1000)
// }).then((data) => {
// console.log(data)
// }, (e) => {
// console.log(e);
// console.log('111')
// return new Promise((r) => {
// r('success')
// })
// }).catch((e) => {
// console.log('222')
// console.log(e);
// }).then((data) => {
// console.log(data)
// })
// new Promise((resolve, reject) => {
// throw 'Promise Error!'
// // reject(1)
// resolve(1)
// }).then((data) => {
// console.log(data)
// throw 'PPPP'
// }).then((data) => {
// console.log(data)
// }).catch((e) => {
// console.log(e)
// })
// Promise.resolve(Promise.resolve(11)).then((data) => {
// console.log(data)
// }, e => console.log(e))
// async function test() {
// const a = await new Promise<number>((r) => {
// console.log(0)
// setTimeout(() => r(1), 1000)
// })
// console.log(a)
// return a;
// }
// test();
// Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)]).then(d => console.log(d)).catch(e => console.log(e))
// Promise.reject(1).finally().finally().then().catch().then((d) => {
// console.log('then', d);
// }).catch((e) => {
// console.log(e)
// }).then((d) => {
// console.log('then', d);
// }).catch((e) => {
// console.log(e)
// }).finally(() => {
// console.log('The end')
// })
// Promise.race([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => j(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)
// Promise.all([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => r(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)
// Promise.allSettled([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => j(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)
// const np = new Promise((r, j) => {
// // setTimeout(r, 0, 1)
// r(1)
// console.log(111)
// })
// console.log(0)
// np.then(d => {
// console.log(d)
// });
// new Promise(() => {
// setTimeout(() => {
// throw 1
// }, 1000)
// }).catch(console.log)