24. Promise
大约 1 分钟
24. Promise
1. 不考虑异步情况的 Promise
// 首先是不考虑异步情况的话
export class Promise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
const resolve = (value) => {
// 成功回调
if (this.state === 'pending') {
this.state = 'fullfilled'
this.value = value
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
}
}
try {
executor(resolve, reject)
}
catch (error) {
reject(error)
}
}
// then 方法有两个参数,表示成功函数和失败函数
// 把获取到的值传入到对应的函数
then(onFinished, onRejected) {
// if (this.state === "pending") {
// }
if (this.state === 'fullfilled')
onFinished(this.value)
if (this.state === 'rejected')
onRejected(this.reason)
}
}
2. 考虑异步情况的 Promise
我们按照 setTimeout
为例,setTimeOut(function, delay, args...)
:
- 函数名:那么等
delay
以后再去调用函数 - 函数:那么直接会调用函数
- 箭头函数包裹着的函数:等待
delay
以后调用
// 考虑异步情况的 Promise
export class Promise {
constructor(excutor) {
// 状态
this.state = 'pending'
this.value = undefined
this.reason = undefined
// 回调函数记录
this.OnResolvedCallbacks = []
this.OnRejectedCallbacks = []
// 成功回调
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fullfilled'
this.value = value
this.OnResolvedCallbacks.forEach(fn => fn())
}
}
// 失败回调
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.OnRejectedCallbacks.forEach(fn => fn())
}
}
try {
excutor(resolve, reject)
}
catch (error) {
reject(error)
}
}
then(onFinished, onRejected) {
if (this.state === 'pending') {
// 以 setTimeout 为例,就是 delay 之前,不知道状态
this.OnResolvedCallbacks.push(() => {
onFinished(this.value)
})
this.OnRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
if (this.state === 'rejected')
onRejected(this.reason)
if (this.state === 'fullfilled')
onFinished(this.value)
}
}
3. 考虑 Promise 链式调用情况
为了解决 Promise
的链式调用,所以第一次 then
的返回值是一个 Promise
对象,后续的每次 then
,都需要借助上一个的返回值,如果没有那么就是 undefined
。
// 解决链式调用,也就是第一次 then 的返回值是一个 Promise 对象
export class Promise {
constructor(excutor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
// 数组存放状态函数回调
this.OnResolvedCallbacks = []
this.OnRejectedCallbacks = []
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fullfilled'
this.value = value
this.OnRejectedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.OnRejectedCallbacks.forEach(fn => fn())
}
}
try {
excutor(resolve, reject)
}
catch (error) {
reject(error)
}
}
then(onFinished, onRejected) {
// 第一次会返回一个 Promise
const Promise2 = new Promise((resolve, reject) => {
if (this.state === 'pending') {
// 成功
this.OnResolvedCallbacks.push(() => {
const x = onFinished(this.value)
resolvePromise(Promise2, x, resolve, reject)
})
// 失败
this.OnRejectedCallbacks.push(() => {
const x = onRejected(this.reason)
resolvePromise(Promise2, x, resolve, reject)
})
}
// 成功状态
if (this.state === 'fullfilled') {
const x = onFinished(this.value)
resolvePromise(Promise2, x, resolve, reject)
}
// 失败状态
if (this.state === 'rejected') {
const x = onRejected(this.reason)
resolvePromise(Promise2, x, resolve, reject)
}
})
return Promise2
}
}
4. 实现 resolvePromise
我们来实现一下,resolvePromise
函数,其用于判断返回值:
x === promise2
则错误x
的类型不是函数也不是Object
,那么就直接进入resolve
- 否则的话,判断
x
的then
类型,如果为函数,那么一定是Promise
,然后判断这个时成功还是失败 - 否则的话,直接
resolve
// resolvePromise 就是用来判断返回值是什么的
// x === promise2 => 错误
// x 的类型不是函数也不是 Object,那么就直接进入 resolve
// 否则的话,判断 x的 then 类型,如果为函数,那么一定是 Promise,然后判断这个时成功还是失败
// 否则的话,直接 resolve
export const resolvePromise = function (Promise2, x, resolve, reject) {
if (x === Promise2) {
// 直接报错
return reject(new TypeError('Chaining cycle detected for promise'))
}
// 防止多次调用
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 那么可能是 Promise
// 接下来判断 x.then 如果为 func,那么一定是 Promise
const then = x.then
if (typeof then === 'function') {
// 那么一定是 Promise
// this 指向 x
then.call(x, (y) => {
// 成功回调
if (called)
return
called = true
resolvePromise(Promise2, y, resolve, reject)
}, (err) => {
// 失败
if (called)
return
called = true
resolvePromise(Promise2, err, resolve, reject)
})
}
}
catch (error) {
// 如果调用过来,直接返回
if (called)
return
called = true
reject(error)
}
}
else {
resolve(x)
}
}
5. 完整 Promise 版本
因为 then
的两个参数 onFinished
和 onRejected
:
- 不是必须的,如果是非函数,那么需要被忽略
- 不是同步的,必须是被异步调用的,这就需要用
setTimeout
包裹,并且使用try-catch
进行错误捕捉
export class Promise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
}
catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// onFulfilled 如果不是函数,就忽略 onFulfilled,直接返回 value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
// onRejected 如果不是函数,就忽略 onRejected,直接扔出错误
onRejected = typeof onRejected === 'function'
? onRejected
: (err) => {
throw err
}
const promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
}
catch (e) {
reject(e)
}
}, 0)
};
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 如果报错
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
}
catch (e) {
reject(e)
}
}, 0)
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
}
catch (e) {
reject(e)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
}
catch (e) {
reject(e)
}
}, 0)
})
};
})
// 返回 promise,完成链式
return promise2
}
}