class Promise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(fn) {
this.status = Promise.PENDING
this.value = null;
this.callbacks = []
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.status !== Promise.PENDING) return false
this.status = Promise.FULFILLED
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => callback.onFulfilled(value))
});
}
reject(reason) {
if (this.status !== Promise.PENDING) return false
this.status = Promise.REJECTED
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => callback.onRejected(reason))
});
}
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled instanceof Function ? onFulfilled : () => this.value
onRejected = onRejected instanceof Function ? onRejected : () => this.value
let promise = new Promise((resolve, reject) => {
if (this.status === Promise.FULFILLED) {
setTimeout(() => {
this.parse(promise, onFulfilled(this.value), resolve, reject)
});
}
if (this.status === Promise.REJECTED) {
setTimeout(() => {
this.parse(promise, onRejected(this.value), resolve, reject)
});
}
if (this.status === Promise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise, onFulfilled(value), resolve, reject)
},
onRejected: value => {
this.parse(promise, onRejected(value), resolve, reject)
}
})
}
})
return promise
}
parse(promise, result, resolve, reject) {
if (promise == result) {
throw new TypeError('Chaining cycle detected')
}
try {
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
static reject(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
reject(value)
}
})
}
static all(promises) {
let arr = []
return new Promise((resolve, reject) => {
promises.forEach((el, index) => {
el.then(
res => {
arr[index] = res
if (arr.length === promises.length) {
resolve(arr)
}
}, err => {
reject(err)
})
})
})
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.map(el => {
el.then(resolve, reject)
})
})
}
}