const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const Promise = function (executor) {
if (!(executor instanceof Function)) {
throw 'executor must be a function'
}
this.state = PENDING
this.result = undefined
this.callback = []
const _onResolve = function (value) {
if (this.state !== PENDING) return
this.state = FULFILLED
this.result = value
if (this.callback.length > 0) {
this.callback.forEach(item => {
item.onResolved()
})
}
}
const _onReject = function (value) {
if (this.state !== PENDING) return
this.state = REJECTED
this.result = value
if (this.callback.length > 0) {
this.callback.forEach(item => {
item.onRejected()
})
}
}
try {
executor(_onResolve.bind(this), _onReject.bind(this))
} catch (error) {
_onReject.call(this, error)
}
}
Object.assign(Promise.prototype, {
then(onResolved, onRejected) {
if (!(onResolved instanceof Function)) {
onResolved = value => value
}
if (!(onRejected instanceof Function)) {
onRejected = reason => {
throw reason
}
}
return new Promise(
function (resolve, reject) {
const _common = function (cb) {
setTimeout(() => {
try {
const value = cb(this.result)
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
} catch (error) {
reject(error)
}
})
}
if (this.state === FULFILLED) {
_common.call(this, onResolved)
} else if (this.state === REJECTED) {
_common.call(this, onRejected)
} else {
this.callback.push({
onResolved: _common.bind(this, onResolved),
onRejected: _common.bind(this, onRejected)
})
}
}.bind(this)
)
},
catch(onRejected) {
return this.then(undefined, onRejected)
}
})
export default Promise