const PENDDING = "pendding";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function runMicroMask(callback) {
if (this.MutationObserver) {
const observer = new MutationObserver(callback);
const div = document.createElement("div");
observer.observe(div, {
childList: true
})
div.innerHTML = "123";
}else if (process && process.nextTick) {
process.nextTick(callback);
}else {
setTimeout(callback, 0);
}
}
function isPromise(obj) {
return !!(obj && typeof obj === "object" && typeof obj.then === "function")
}
class MyPromise {
constructor(executor) {
this._state = PENDDING;
this._value = undefined;
this._handlers = [];
try {
executor(this._resolve.bind(this), this._rejected.bind(this));
}catch(error) {
this._rejected(error);
}
}
_runHandler({ executor, state, resolve, rejected }) {
runMicroMask(()=> {
if (this._state !== state) return ;
if (typeof executor !== "function") {
state === FULFILLED ? resolve(this._value) : rejected(this._value);
return ;
}
try {
const result = executor(this._value);
if (isPromise(result)) {
result.then(resolve, rejected)
}else {
resolve(result)
}
}catch(error) {
rejected(error);
}
})
}
_runQueues() {
if (this._state === PENDDING) return ;
while(this._handlers[0]) {
const handler = this._handlers[0];
this._runHandler(handler);
this._handlers.shift();
}
}
_pushHandlers(executor, state, resolve, rejected) {
this._handlers.push({
executor,
state,
resolve,
rejected
})
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, rejected)=> {
this._pushHandlers(onFulfilled, FULFILLED, resolve, rejected);
this._pushHandlers(onRejected, REJECTED, resolve, rejected);
this._runQueues();
})
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onSettled) {
return this.then(data => {
onSettled();
return data;
},reason => {
onSettled();
return reason;
})
}
static resolve(data) {
if (data instanceof MyPromise) {
return data;
}
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject);
}else {
resolve(data);
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
})
}
static all(promises) {
return new MyPromise((resolve, reject) => {
try {
let count = 0;
let resolveCount = 0;
let result = [];
if (promises.length === 0) {
resolve(result);
}
for (const pro of promises) {
let i = count;
count++;
MyPromise.resolve(pro).then(res => {
resolveCount++;
result[i] = res;
if (resolveCount === count) {
resolve(result);
}
}, reject)
}
}catch(error) {
reject(error);
}
})
}
static allSettled(promises) {
let pro = [];
for (const p of promises) {
pro.push(
MyPromise.resolve(p).then(value => ({
state: FULFILLED,
value
}), reason => ({
state: REJECTED,
reason
}))
)
}
return MyPromise.all(pro)
}
static race(promises) {
return new MyPromise((resolve, reject) => {
for (const p of promises) {
MyPromise.resolve(p).then(resolve, reject)
}
})
}
_change(state, value) {
if (this._state !== PENDDING) return;
this._state = state;
this._value = value;
this._runQueues();
}
_resolve(data) {
this._change(FULFILLED, data);
}
_rejected(error) {
this._change(REJECTED, error);
}
}