/**
* author:lsr
* desc:手写Promise
* date:20220118
*/
class MyPromise {
state = 'pending'
value = undefined
reason = undefined
resolveCallbacks = []
rejectCallbacks = []
constructor(fn) {
const resolveHandler = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(f => f())
}
}
const rejectHandler = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.rejectCallbacks.forEach(f => f())
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (err) {
rejectHandler(err)
}
}
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (value) => value
fn2 = typeof fn2 === 'function' ? fn2 : (err) => err
if (this.state === 'pending') {
return new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch (err) {
reject(err)
}
})
this.rejectCallbacks.push(() => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (err) {
reject(err)
}
})
})
} else if (this.state === 'fulfilled') {
return new MyPromise((resolve, reject) => {
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch (err) {
reject(err)
}
})
} else if (this.state === 'rejected') {
return new MyPromise((resolve, reject) => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (err) {
reject(err)
}
})
}
}
catch(fn) {
return this.then(null, fn)
}
}
MyPromise.all = function(list = []) {
return new MyPromise((resolve, reject) => {
let count = 0
let results = []
list.forEach(p => {
p.then(res => {
count++
results.push(res)
if (count === list.length) {
resolve(results)
}
}).catch(err => reject(err))
})
})
}
MyPromise.race = function (list = []) {
return new MyPromise((resolve, reject) => {
let flag = false
list.forEach(p => {
p.then(res => {
if (!flag) {
flag = true
resolve(res)
}
}).catch(err => reject(err))
})
})
}
MyPromise.resolve = function(value) {
return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function(error) {
return new MyPromise((resolve, reject) => reject(error))
}