实现 Promise 原理 (实现部分常用方法)
- resolove() 成功的回调函数, 参数为成功的返回值
- reject() 失败的回调函数, 参数为失败的返回值
- then() 链式调用 参数为 resolve() 和 reject() 回调函数
- all() all方法, 参数为数组, 全部执行完才输出执行结果, 返回值为数组
- race() race方法, 参数为数组(同all方法), 第一个执行完成,其他代码不再执行, 输出第一个执行结果
- catch() catch执行过程中一旦发生错误,便执行catch方法, 参数为 抓取的错误对象
- done()
- finally()
let nextTick = (function () {
let callbacks = []
let counter = 1
function handler() {
let copy = callbacks.slice()
callbacks = []
copy.forEach(cb => {
cb()
})
}
let node = document.createElement('div')
let observer = new MutationObserver(handler)
observer.observe(node, {
childList: true
})
return function (cb) {
callbacks.push(cb)
counter = (counter + 1) % 2
node.innerHTML = counter
}
})()
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise2 {
static all(promises) {
return new this((resolve, reject) => {
let promiseNum = promises.length
let resolvedNum = 0
let resolvedValues = new Array(promiseNum)
for (let i = 0; i < promiseNum; i++) {
this.resolve(promises[i]).then(
val => {
resolvedNum++
resolvedValues[i] = val
if (resolvedNum === promiseNum) {
resolve(resolvedValues)
}
},
reason => {
reject(reason)
}
)
}
})
}
static race(promises) {
return new this((resolve, reject) => {
let promisesLength = promises.length
for (let i = 0; i < promisesLength; i++) {
this.resolve(promises[i]).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
}
})
}
static resolve(value) {
if (value instanceof this) {
return value
}
return new this((resolve, reject) => {
resolve(value)
})
}
static reject(reason) {
return new this((resolve, reject) => {
reject(reason)
})
}
constructor(executor) {
this.status = PENDING
this.value = null
this.reason = null
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (value instanceof this.constructor) {
value.then(resolve, reject)
return
}
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
nextTick(() => {
this.onFulfilledCallbacks.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
nextTick(() => {
this.onRejectedCallbacks.forEach((fn => {
fn(this.reason)
}))
})
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
const p2 = new this.constructor((resolve, reject) => {
if (this.status === FULFILLED) {
nextTick(() => {
try {
let callbackValue = onFulfilled(this.value)
resolve(callbackValue)
} catch (error) {
reject(error)
}
})
}
if (this.status === REJECTED) {
nextTick(() => {
try {
let callbackValue = onRejected(this.reason)
resolve(callbackValue)
} catch (error) {
reject(error)
}
})
}
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
let callbackValue = onFulfilled(this.value)
resolve(callbackValue)
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(() => {
try {
let callbackValue = onRejected(this.reason)
resolve(callbackValue)
} catch (error) {
reject(error)
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(null, onRejected)
}
}
Promise2.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected)
.catch(function (reason) {
setTimeout(() => {
throw reason
})
})
}
Promise2.prototype.finally = function (callback) {
let p = this.constructor
return this.then(
value => p.resolve(callback()).then(() => value),
reason => p.resolve(callback())).then(() => { throw reson })
}