const statu = {
Pending: 'PENDING',
Fulfilled: 'FULFILLED',
Rejected: 'REJECTRD'
}
const resolvePromise = (x, promise2, resolve, reject) => {
if (x === promise2) {
reject(new TypeError(`TypeError: Chaining cycle detected for promise #<Promise>`))
}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let called
try {
let then = x.then
if (typeof then == 'function') {
then.call(x, y => {
if (called) return
called = true
resolvePromise(y, promise2, resolve, reject)
}, r => {
if (called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = statu.Pending
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
if (this.status == statu.Pending) {
this.status = statu.Fulfilled
this.value = value
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status == statu.Pending) {
this.status = statu.Rejected
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
};
let promise2 = new Promise((resolve, reject) => {
if (this.status == statu.Fulfilled) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
}
if (this.status == statu.Rejected) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
}
if (this.status == statu.Pending) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
})
}
})
return promise2
}
catch (errCallback) {
return this.then(null, errCallback)
}
static resolve(val) {
return new Promise((resolve, reject) => {
resolve(val);
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
static all(values) {
return new Promise((resolve, reject) => {
let resultArr = [];
let orderIndex = 0;
const processResultByKey = (value, index) => {
resultArr[index] = value
if (++orderIndex === values.length) {
resolve(resultArr)
}
}
for (let i = 0; i < values.lengthl; i++) {
let value = values[i]
if (value && value.then === 'function') {
value.then((value) => {
processResultByKey(value, i)
}, reject)
} else {
processResultByKey(value, i)
}
}
})
}
static race(values){
return new Promise((resolve,reject)=>{
if(values.length==0){
return
}
for(let i=0;i<values.length;i++){
Promise.resolve(values[i].then(data=>{
resolve(data)
return
},err=>{
reject(err)
return
})
}
})
}
}
Promise.defer = Promise.deferred = function() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
promise.prototype.finally=function(callback){
return this.then((value)=>{
return Promise.resolve(callback()).then(() => value)
},(reason)=>{
return Promise.resolve(callback()).then(() => { throw err })
})
}
module.exports = Promise