class HD {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executor) {
this.status = HD.PENDING
this.value = null
this.callbakcs = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve (value) {
if (this.status === 'pending') {
this.status = HD.FULFILLED
this.value = value
setTimeout(() => {
this.callbakcs.map((callback) => {
callback.onFulfile(value)
})
})
}
}
reject (reason) {
if (this.status === 'pending') {
this.status = HD.REJECTED
this.value = reason
setTimeout(() => {
this.callbakcs.map((callback) => {
callback.onRejected(reason)
})
})
}
}
then (onFulfile, onRejected) {
if (typeof onFulfile != 'function') {
onFulfile = () => this.value
}
if (typeof onRejected != 'function') {
onRejected = () => this.value
}
let promise = new HD((resolve, reject) => {
if (this.status === HD.PENDING) {
this.callbakcs.push({
onFulfile: value => {
this.parse(promise, onFulfile(value), resolve, reject)
},
onRejected: value => {
this.parse(onRejected(value), resolve, reject)
}
})
}
if (this.status === HD.FULFILLED) {
setTimeout(() => {
this.parse(promise, onFulfile(this.value), resolve, reject)
})
}
if (this.status === HD.REJECTED) {
setTimeout(() => {
this.parse(promise, onRejected(this.value), resolve, reject)
})
}
})
return promise
}
parse (promise, result, resolve, reject) {
if (promise === result) {
throw new TypeError('chaining')
}
try {
if (result instanceof HD) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
static resolve (value) {
return new HD((resolve, reject) => {
if (value instanceof HD) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
static reject (value) {
return new HD((resolve, reject) => {
if (value instanceof HD) {
value.then(resolve, reject)
} else {
reject(value)
}
})
}
static all (promises) {
return new HD((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(
value => {
values.push(value)
if (values.length === promises.length) {
resolve(values)
}
},
reason => {
reject(reason)
}
)
})
})
}
static race (promises) {
return new HD((resolve, reject) => {
promises.map(promise => {
promise.then(
value => {
resolve(value)
},
reason => {
reject(reason)
})
})
})
}
}