提前预加载应用

有这样一个场景:
页面的数据量较大,通过缓存类将数据缓存在了本地,下一次可以直接使用缓存,在一定数据规模时,本地的缓存初始化和读取策略也会比较耗时。这个时候我们可以继续等待缓存类初始完成并读取本地数据,也可以不等待缓存类,而是直接提前去后台请求数据。两种方法最终谁先返回的时间不确定。那么为了让我们的数据第一时间准备好,让用户尽可能早地看到页面,我们可以通过 Promise 来做加载优化。

实现的思路是:页面加载之后,立马调用一下Promise封装的后台请求,请求后台的数据,同时准备好初始化缓存类,并且调用Promise封装的本地读取数据逻辑,最后在显示数据的时候,谁先返回就用谁的

中断场景的应用

实际应用中,还有这样一种场景:我们正在发送多个请求用于请求数据,等待完成后将数据插入到不同的 dom 元素中,而如果在中途 dom 元素被销毁了(比如 react 在 useEffect 中请求的数据时,组件销毁),这时就可能会报错。因此我们需要提前中断正在请求的 Promise,不让其进入到 then 中执行回调。

useEffect(() => {
    let dataPromise = new Promise(...);
    let data = await dataPromise();
    // TODO 接下来处理 data,此时本组件可能已经销毁了,dom 也不存在了,所以需要在下面对 Promise 进行中断

    return (() => {
      // TODO 组件销毁时,对 dataPromise 进行中断或取消
    })
});

我们可以对生成的 Promise 对象进行再一次包装,返回一个新的 Promise 对象,而新的对象上被我们增加了 cancel 方法,用于取消。这里的原理就是在 cancel 方法里面去阻止 Promise 对象执行 then()方法。

下面构造了一个 cancelPromise 用于和原始 Promise 竞速,最终返回合并后的 Promise,外层如果调用了 cancel 方法,cancelPromise 将提前结束,整个 Promise 结束。

const getPromiseWithCancel = (promise: Promise<any>) => {
    let cancel = (v?: any) => {};
    let isCancel = false;
    const cancelPromise = new Promise((resolve, reject) => {
        cancel = e => {
            isCancel = true;
            reject(e)
        }
    })

    const groupPromise = Promise.race([promise, cancelPromise]).catch((e) => {
        if (isCancel) {
            // 主动触发的时候,不会触发外层的catch
            return new Promise(() => {})
        } else {
            return Promise.reject(e)
        }
    })
    return Object.assign(groupPromise, { cancel })
}

// use here 
const originPromise = new Promise((resolve, reject) => {
    resolve(setTimeout(() => {
        console.log('time here');
    },1000))
})

const promiseWithCancel = getPromiseWithCancel(originPromise)

promiseWithCancel.then((data) => {
    console.log('渲染: '+ data);
})

promiseWithCancel.cancel()

Promise深入理解:控制反转

Promise与callback有一个很大的不同点,那就是控制权的所在层,也就是所谓的控制权反转
callback情境下,回调函数是由业务层传递给逻辑封装层,封装层在业务结束后调用回调函数

而Promise模式下,业务层并没有把回调函数直接传递给封装层( Promise 对象内部),封装层在任务结束时也不知道要做什么回调,只是通过resolve或reject来通知到 业务层,从而由业务层自己在 then() 或 reject() 里面去控制自己的回调执行。

说白了,callback模式下,回调函数的执行控制权在封装层。 Promise模式下,回调函数的控制权在业务层

最后修改:2023 年 02 月 22 日
收款不要了,给孩子补充点点赞数吧