想必每个JS同学在工作中都会用到Promise, 但是一般来说Promise的内部流程我们不会去过多关心和干预。 今天教大家一个新思路, 截断Promise,在Promise的过程中间插入自己的代码。
这个操作在React-Query源码中出现,读到这里时着实让我大开眼界. 对React-Query感兴趣的小伙伴可以阅读我的专栏: 全网最细 React-Query源码探秘 - 不月阳九的专栏 - 掘金 (juejin.cn)
关键点: 执行器函数
首先,我们需要知道Promise的执行器函数的特性
- 执行器函数: new Promise时传入的函数
- 执行器函数在new Promise的时候会立即同步执行
- 执行器函数接收两个参数,resolve和reject
new Promise((resolve,reject)=>{})
.then() resolve,reject到底是什么
Promise在构建初期,会在最顶上模拟一个函数队列,
而.then(fn)就是将函数fn推入这个队列,
const arr = [] // 保存了多个函数
new Promise()
.then(fn1)
.then(fn2)
.then(fn3) // 实际上就是将fn1,fn2,fn3依次推入这个队列
而执行器函数中的resolve,reject,会遍历这个调用栈中的函数,并执行
// 模拟的resolve函数
function resolve(value) {
// 判断PromiseState是否为pending (如果不是就不能进行状态修改 不执行执行器函数)
if (that.PromiseState === 'pending') {
that.PromiseState = 'resolved'
that.PromiseResult = value
//将其变为异步操作(放到setTimeout里)
setTimeout(() => {
// 循环数组 调用所有成功回调
that.callbacks.forEach(item => {
item.onResolved(that.PromiseResult)
})
})
}
}
可以得出结论,实际上resolve和reject就是启动这些函数的开关,resolve()会执行所有的onResolve函数,反之
new Promise((resolve,reject)=>{
resolve() // 当执行了resolve(),才会执行then中的函数 打印'执行'
})
.then((res)=>{console.log('执行')})
修改这些启动器
知道了resolve的作用,我们就可以将这些启动器拿出来,在特定的时机执行
const promiseResolve;
const promiseReject;
let isResolved = false //执行了自定义的res或rej后会改变 之后不会继续执行
new Promise((resolve, reject) => {
promiseResolve = resolve // 将启动器保存到外部
promiseReject = reject
})
// 封装自己的resolve,reject启动器
// 模拟Promise的流程 状态只能改变一次
const resolve = ()=>{
if (isResolved) return
console.log('在执行.then函数之前执行此代码')
isResolved = true
promiseResolve() // 再执行真正的resolve
}
const reject = ()=>{
if (isResolved) return
console.log('在执行.then的resolve函数之前执行此代码')
isResolved = true
promiseReject() // 再执行真正的resolve
}
这样一来 我们就通过将启动器拿出来 实现了Promise的截断 实际上就是在Promise外部,再包一层模拟的Promise逻辑, 从而达到类似截断Promise的效果
我们可以在实际开发中,定义些许回调函数,插入Promise中