如何在Promise.then()执行之前插入自己的代码? Promise的作用域提升

285 阅读2分钟

想必每个JS同学在工作中都会用到Promise, 但是一般来说Promise的内部流程我们不会去过多关心和干预。 今天教大家一个新思路, 截断Promise,在Promise的过程中间插入自己的代码。

这个操作在React-Query源码中出现,读到这里时着实让我大开眼界. 对React-Query感兴趣的小伙伴可以阅读我的专栏: 全网最细 React-Query源码探秘 - 不月阳九的专栏 - 掘金 (juejin.cn)

关键点: 执行器函数

首先,我们需要知道Promise的执行器函数的特性

  1. 执行器函数: new Promise时传入的函数
  2. 执行器函数在new Promise的时候会立即同步执行
  3. 执行器函数接收两个参数,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中