const PENDING = 'pendind'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected';
function runMicroTask(callback) {
setTimeout(callback, 0)
}
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function')
}
class MyPromise {
constructor(exector) {
this._value = undefined;
this._state = PENDDING;
this._handles = [];
try {
exector(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
this._reject(error)
}
}
_changeState(state, value) {
if (this._state !== PENDDING) {
return
}
this._state = state;
this._value = value;
this._runHandles()
}
_resolve(data) {
this._changeState(FULFILLED, data)
}
_reject(reason) {
this._changeState(REJECTED, reason)
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._handles.push({ onFulfilled, FULFILLED, resolve, reject })
this._handles.push({ onRejected, REJECTED, resolve, reject })
this._runHandles()
})
}
_runOneHandles({ exector, state, resolve, reject }) {
runMicroTask(() => {
if (this._state !== state) {
return
}
if (typeof exector !== 'function') {
this._state === FULFILLED ? resolve(this._value) : reject(this._value)
return
}
try {
const result = exector(this._value)
if (isPromise(result)) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
_runHandles() {
if (this._state === PENDDING) {
return
}
while (this._handles[0]) {
this._runOneHandles(this._handles[0])
this._handles.shift()
}
}
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 catch(onRejected) {
return this.then(null, onRejected)
}
static race(proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then(resolve, reject)
}
})
}
static all(proms) {
return new MyPromise((resolve, reject) => {
try {
const result = [];
const count = 0;
const fulfilleCount = 0;
for (const p of proms) {
let index = count;
count++;
MyPromise.resolve(p).then((data) => {
fulfilleCount++;
result[index] = data
if (fulfilleCount === count) {
resolve(result)
}
}, reject)
}
if (count === 0) {
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
static AllSettled(proms) {
const ps = [];
for (const p of proms) {
ps.push(MyPromise.resolve(p).then(((value) => ({state: FULFILLED, value})), (reason) => ({state: REJECTED, reason})))
}
return MyPromise.all(ps)
}
static finally(onSettled){
return this.then((data) => {
onSettled()
return data
}, (reason) => {
onSettled()
throw reason
})
}
}