const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
static resolve = (paramter) => {
if (paramter instanceof MyPromise) {
return paramter;
}
return new MyPromise((resolve) => {
resolve(paramter);
});
};
static reject = (reason) => {
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
status = PENDING;
value = null;
reason = null;
onFulfilledCallbacks: any = [];
onRejectedCallbacks: any = [];
resolve = (value) => {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(value);
}
}
};
reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason);
}
}
};
then(onFulfilled, onRejected) {
const realOnFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
const realOnRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
const promise = new Promise<void>((resolve, reject) => {
const microtask = (onRealHandle, value) => {
queueMicrotask(() => {
try {
const x = onRealHandle(value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
});
};
if (this.status === FULFILLED) {
microtask(realOnFulfilled, this.value);
} else if (this.status === REJECTED) {
microtask(realOnRejected, this.reason);
} else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() => {
microtask(realOnFulfilled, this.value);
});
this.onRejectedCallbacks.push(() => {
microtask(realOnRejected, this.reason);
});
}
});
return promise;
}
}
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
if (typeof x === "object" || typeof x === "function") {
if (x === null) {
return resolve(x);
}
let then;
try {
then = x.then;
} catch (error) {
return reject(error);
}
if (typeof then === "function") {
let called = false;
try {
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} catch (error) {
if (called) return;
reject(error);
}
} else {
resolve(x);
}
} else {
resolve(x);
}
}
module.exports = MyPromise;