17 手写 Promise
Promise 规范
https://promisesaplus.com/
手写 Promise-结构的设计
// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
console.log('resolve被调用')
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
console.log('reject被调用')
}
}
executor(resolve, reject)
}
}
手写 Promise-then 方法设计
// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
queueMicrotask(() => {
this.value = value
this.onFulfilled(this.value)
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
queueMicrotask(() => {
this.reason = reason
this.onRejected(this.reason)
})
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
手写 Promise-then 方法优化一
// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach((fn) => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach((fn) => {
fn(this.reason)
})
})
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
onFulfilled(this.value)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
onRejected(this.reason)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
}
手写 Promise-then 方法优化二
// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
// 工具函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class HYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach((fn) => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach((fn) => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
return new HYPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
}
手写 Promise-catch 方法设计
class HYPromise {
catch(onRejected) {
this.then(undefined, onRejected)
}
}
手写 Promise-finally 方法设计
class HYPromise {
finally(onFinally) {
this.then(
() => {
onFinally()
},
() => {
onFinally()
}
)
}
}
手写 Promise-resolve-reject 方法
class HYPromise {
static resolve(value) {
return new HYPromise((resolve) => resolve(value))
}
static reject(reason) {
return new HYPromise((resolve, reject) => reject(reason))
}
}
手写 Promise-all-allSettled 方法
class HYPromise {
static all(promises) {
// 问题关键: 什么时候要执行resolve, 什么时候要执行reject
return new HYPromise((resolve, reject) => {
const values = []
promises.forEach((promise) => {
promise.then(
(res) => {
values.push(res)
if (values.length === promises.length) {
resolve(values)
}
},
(err) => {
reject(err)
}
)
})
})
}
static allSettled(promises) {
return new HYPromise((resolve) => {
const results = []
promises.forEach((promise) => {
promise.then(
(res) => {
results.push({ status: PROMISE_STATUS_FULFILLED, value: res })
if (results.length === promises.length) {
resolve(results)
}
},
(err) => {
results.push({ status: PROMISE_STATUS_REJECTED, value: err })
if (results.length === promises.length) {
resolve(results)
}
}
)
})
})
}
}
手写 Promise-race-any 方法
class HYPromise {
static race(promises) {
return new HYPromise((resolve, reject) => {
promises.forEach((promise) => {
// promise.then(res => {
// resolve(res)
// }, err => {
// reject(err)
// })
promise.then(resolve, reject)
})
})
}
static any(promises) {
// resolve必须等到有一个成功的结果
// reject所有的都失败才执行reject
const reasons = []
return new HYPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, (err) => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}