const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
function resolvePromise(promise2,x,resolve,reject) {
if(promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise> --'))
}
if ((typeof x === 'object' && x!== null) || typeof x === 'function') {
try{
let then = x.then;
if (typeof then === 'function') {
then.call(x,(data) => {
resolvePromise(promise2,data,resolve,reject)
},(err) => {
reject(err)
})
} else {
resolve(x)
}
} catch(e) {
reject(e)
}
} else {
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCalllbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === PENDING) {
if (value instanceof Promise) {
value.then(resolve,reject)
return;
}
this.value = value;
this.status = RESOLVED;
this.onResolvedCalllbacks.forEach(fn => fn())
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve,reject)
} catch(e) {
reject(e)
}
}
catch(onrejected) {
return this.then(() =>{},onrejected)
}
then(onfullfilled,onrejected) {
onfullfilled = typeof onfullfilled === 'function' ? onfullfilled : v => v
onrejected = typeof onrejected === 'function' ? onrejected : e => {throw e}
const promise2 = new Promise((resolve,reject) => {
if(this.status === RESOLVED) {
setTimeout(() => {
try{
resolvePromise(promise2,onfullfilled(this.value),resolve,reject);
} catch(e) {
reject(e)
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try{
resolvePromise(promise2,onrejected(this.reason),resolve,reject);
}catch(e) {
reject(e)
}
}, 0);
}
if (this.status === PENDING) {
this.onResolvedCalllbacks.push(() => {
setTimeout(() => {
try {
resolvePromise(promise2,onfullfilled(this.value),resolve,reject);
}catch(e){
reject(e)
}
}, 0);
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
resolvePromise(promise2,onrejected(this.reason),resolve,reject);
}catch(e) {
reject(e)
}
}, 0);
})
}
})
return promise2
}
}
module.exports = Promise