const PENNDIN = 'PEDDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
const mPromise = function (executor) {
this.PromiseStatus = PENNDIN
this.PromiseResult = null
this.fulfilledCallBackList = []
this.rejectedCallBackList = []
const resolve = (data) => {
if (this.PromiseStatus !== PENNDIN) {
return
}
this.PromiseStatus = FULFILLED
this.PromiseResult = data
this.fulfilledCallBackList.forEach(fn => fn())
}
const reject = (data) => {
if (this.PromiseStatus !== PENNDIN) {
return
}
this.PromiseStatus = REJECTED
this.PromiseResult = data
this.rejectedCallBackList.forEach(fn => fn())
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
mPromise.resolve = function (val) {
if (val instanceof mPromise) {
return val
}
return new mPromise((resolve, reject) => {
if (val && typeof val === 'bigint' && typeof val.then === 'function') {
setTimeout(() => {
val.then(resolve, reject)
})
} else {
resolve(val)
}
})
}
mPromise.reject = function (val) {
return new mPromise((resolve, reject) => {
reject(val)
})
}
mPromise.all = function (pmList) {
pmList = [...pmList]
return new mPromise((resolve, reject) => {
let idx = 0
let result = []
if (pmList.length === 0) {
resolve(result)
} else {
const rowValue = (i, val) => {
result[i] = val
idx += 1
if (idx === pmList.length) {
resolve(result)
}
}
for (let i = 0; i < pmList.length; i++) {
mPromise.resolve(pmList[i].then((val) => {
rowValue(i, val)
}, (err) => {
reject(err)
return
}))
}
}
})
}
mPromise.race = function (pmList) {
pmList = [...pmList]
return new mPromise((resolve, reject) => {
if (pmList.length === 0) {
return
} else {
for (let i = 0; i < pmList.length; i++) {
mPromise.resolve(pmList[i].then((val) => {
resolve(val)
return
}, (err) => {
reject(err)
return
}))
}
}
})
}
function resolvePromise(newPromise, val, resolve, reject) {
let self = this
if (newPromise === val) {
reject(new TypeError('链循环'))
}
if (val && typeof val === 'object' || typeof val === 'function') {
let isReject = false
try {
let then = val.then
if (typeof then === 'function') {
then.call(val, (v) => {
if (isReject) {
return
}
isReject = true
resolvePromise(newPromise, v, resolve, reject)
}, (e) => {
if (isReject) {
return
}
isReject = true
reject(e)
})
} else {
if (isReject) {
return
}
resolve(val)
}
} catch (error) {
if (isReject) {
return
}
reject(error)
}
}
}
mPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
let self = this
let newPromise = new mPromise((resolve, reject) => {
if (self.PromiseStatus === FULFILLED) {
setTimeout(() => {
try {
let val = onFulfilled(self.PromiseResult)
resolvePromise(newPromise, val, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (self.PromiseStatus === REJECTED) {
setTimeout(() => {
try {
let val = onRejected(self.PromiseResult)
resolvePromise(newPromise, val, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (self.PromiseStatus === PENNDIN) {
self.fulfilledCallBackList.push(() => {
setTimeout(() => {
try {
let val = onFulfilled(self.PromiseResult)
resolvePromise(newPromise, val, resolve, reject)
} catch (error) {
reject(error)
}
})
})
self.rejectedCallBackList.push(() => {
setTimeout(() => {
try {
let val = onRejected(self.PromiseResult)
resolvePromise(newPromise, val, resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
})
return newPromise
}
mPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}
mPromise.prototype.finally = function (callBack) {
return this.then((value) => {
return mPromise.resolve(callBack()).then(() => {
return value
})
}, (err) => {
return mPromise.resolve(callBack()).then(() => {
throw err
})
})
}
modele.exports = mPromise