enum enmuStatus {
PENDING = 'pending',
FULFILLED = 'fulfilled',
REJECTED = 'rejected'
}
type DataType = (data?: ResolveAndReject['resolve']) => any | undefined
type ErrorType = (error?: ResolveAndReject['resolve']) => any
type PromiseStatus = 'fulfilled' | 'rejected' | 'pending'
interface HandlersObj {
funState: PromiseStatus
resolve: ResolveAndReject['resolve']
reject: ResolveAndReject['reject']
callback: DataType | undefined
}
interface ResolveAndReject {
resolve(something: any): void
reject(something: any): void
}
interface PromiseInterface {
then(successFunc?: DataType, errorFunc?: ErrorType): void
}
function runMicroTask(callback: any) {
if (globalThis.MutationObserver) {
const p = document.createElement('p');
const observer = new MutationObserver(callback);
observer.observe(p, {
childList: true,
});
p.innerHTML = '1';
} else {
setTimeout(callback, 0);
}
}
export default class MyPromise implements PromiseInterface {
private value: any
private state: PromiseStatus
private handlers: Array<HandlersObj>
constructor(func: (resolve: ResolveAndReject["resolve"], reject: ResolveAndReject['reject']) => void) {
try {
func(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
console.error(error)
}
this.value = null;
this.state = enmuStatus.PENDING;
this.handlers = []
}
private resolve(something: any): void {
this.changeState(enmuStatus.FULFILLED, something)
}
private reject(something: any): void {
this.changeState(enmuStatus.REJECTED, something)
}
private changeState(state: PromiseStatus, value: any) {
if (this.state !== enmuStatus.PENDING) {
return;
}
this.state = state;
this.value = value;
this.runHandler()
}
private runHandler() {
if (this.state === enmuStatus.PENDING) {
return;
}
while (this.handlers[0]) {
this.runOneHandler(this.handlers[0])
this.handlers.shift()
}
}
private runOneHandler({ funState, resolve, reject, callback }: HandlersObj) {
runMicroTask(() => {
if (this.state !== funState) {
return;
}
if (typeof callback !== 'function') {
this.state === enmuStatus.FULFILLED ? resolve(this.value) : reject(this.value)
return;
}
try {
const result = (<DataType>callback)(this.value)
if (result instanceof MyPromise) {
<PromiseInterface>result.then(resolve, reject)
return;
}
resolve(result)
} catch (error) {
reject(error)
console.error(error)
}
})
}
private setHandle(funState: HandlersObj['funState'], resolve: HandlersObj['resolve'], reject: HandlersObj['reject'], callback: HandlersObj['callback']) {
this.handlers.push(
{
funState,
resolve,
reject,
callback
}
)
}
then(successFunc?: DataType, errorFunc?: ErrorType): PromiseInterface {
return new MyPromise((resolve, reject) => {
this.setHandle(enmuStatus.FULFILLED, resolve, reject, successFunc)
this.setHandle(enmuStatus.REJECTED, resolve, reject, errorFunc)
this.runHandler()
})
}
}