const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise{
status = PENDING;
value = undefined;
error = undefined;
successCallbacks = [];
failCallbacks = [];
constructor(executor){
try{
executor(this.resolve, this.reject)
}catch(e){
this.reject(e);
}
}
resolve = (value)=>{
if (this.status === PENDING){
this.status = FULFILLED;
this.value = value;
while(this.successCallbacks.length){
this.successCallbacks.shift()();
}
}
}
reject = (err)=>{
if (this.status === PENDING) {
this.status = REJECTED;
this.error = err;
while (this.failCallbacks.length) {
this.failCallbacks.shift()();
}
}
}
then(successCallback,failCallback){
failCallback = failCallback || (error=> {throw error});
if (!(successCallback instanceof Function)){
successCallback = ()=>this.value
}
let promise2 = new MyPromise((resolve,reject)=>{
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
});
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.error)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
});
} else {
this.successCallbacks.push(()=>{
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
});
});
this.failCallbacks.push(()=>{
setTimeout(() => {
try {
let x = failCallback(this.error)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
});
})
}
})
return promise2;
}
finally(callback){
return this.then(function(res){
return MyPromise.resolve(callback()).then(()=>res)
}, function(err){
return MyPromise.resolve(callback()).then(() => {throw err;})
})
}
catch(fun){
return this.then(undefined, fun)
}
static all(arr){
const result = [];
return new Promise(function(resolve,reject){
function addResult(index,res){
result[index] = res;
if (result.length === arr.length){
resolve(result);
}
}
arr.map((item,idx)=>{
if(item instanceof MyPromise){
item.then(res => addResult(idx, res), reject)
}else{
addResult(idx, item);
}
})
})
}
static resolve(value){
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
}
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise){
return x.then(resolve,reject)
}else{
return resolve(x);
}
}