如何利用 promise 影响代码的执行顺序?
创始人
2024-01-21 06:11:56
0

如何利用 promise 影响代码的执行顺序?

我们写代码的时候,经常会遇到这样的场景。2个不同组件,它们的生命周期本身都是相互独立,毫无关联的,但是它们调用的接口,存在相互依赖的情况。

我举个例子:

开发小程序时候,里面 App 有一个 onLaunchhook,在小程序初始化时调用,而 Page 里也有一个 onLoadhook,在页面加载时被调用。正常的执行顺序为:

// 应用启动
onLaunch(options)
// do sth....
// 页面加载
onLoad(query) 

但是,我们往往也经常遇到这种 case:

async onLaunch(){store.dispatch('set-token',await getToken())
}
async onLoad(){// getUserInfo 依赖 tokensetUserInfo(await getUserInfo())
} 

现在问题来了,依据上面的执行顺序,getTokengetUserInfo 请求实际上是并发执行的。而我们的预期是,先执行 getToken 并设置好全局 token 值之后,才调用 getUserInfo,这样后端才能依据请求携带的,用户 token 信息,来给我们返回指定的数据,不然那就只有一个 401 了。

那么我们如何让它们之间产生调用的依赖关系呢? 实际上很简单 promiseevent-emitter 都是方法之一。接下来我们来构建一个最小化模型。

最小化模型

我们想要 onLoad一部分的代码的执行在 onLaunch特定代码之后。即把一部分并行跑的代码,变更为串行的顺序,同时也允许原先并行运行的方式。

根据描述,我们天然的就想到了 Microtask,它运行在每个事件循环的执行代码,和运行Task后,Rerender 前。

接下来为了实现期望,我们就需要在 onLaunch 中去产生 Promise,然后到 onLoad 中依据 Promise 状态的变化,执行代码。

那么我们就很容易在一个文件中,构建出一个最小化模型,见下方代码:

let promisefunction producer () {console.log('producer start!')promise = new Promise((resolve) => {setTimeout(() => {console.log('promise resolved')resolve(Math.random())}, 2_000)})console.log('producer end!')
}async function consumer () {console.log('consumer start!')console.log(await promise)console.log('consumer end!')
}producer()
consumer() 

这段代码中,我在 producer 创建了一个 promise,在 2sresolve 一个随机数,然后再在 consumer 中,去 await 它的状态,变为 fulfilled 后打印 consumer end!。 当然 async/await 只是语法糖,你用 then/catch 也是可以的,不过使用 await 有一个好处就是,它在面对非 Promise 对象的时候,它会自动把值进行包裹转化成 Promise,即 Promise.resolve(value)

接着,让我们把这个模型进行扩充,变为多文件模型。

// ref.js 创建一个引用
export default {promise: undefined
} 
// producer.js
import ref from './ref.js'export default () => {console.log('producer start!')ref.promise = new Promise((resolve) => {setTimeout(() => {console.log('promise resolved')resolve(Math.random())}, 2_000)})console.log('producer end!')
} 
// consumer.js
import ref from './ref.js'export default async () => {console.log('consumer start!')console.log(await ref.promise)console.log('consumer end!')
} 
// index.js
import producer from './producer.js'
import consumer from './consumer.js'producer()
consumer() 

执行结果同理。

移花接木

根据上述的代码,我们就可以对小程序的开发,进行一系列劫持的操作。我们以 uni-app vue2/3 和原生为例。

// vue2
Vue.mixin({created () {if (Array.isArray(this.$options.onLoad) && this.$options.onLoad.length) {this.$options.onLoad = this.$options.onLoad.map(fn => {return async (params:Record) => {await ref.promisefn.call(this, params)}})}}
})// vue3
const app = createSSRApp(App)
app.mixin({created () {if (this.$scope) {const originalOnLoad = this.$scope.onLoadthis.$scope.onLoad = async (params:Record) => {await ref.promiseoriginalOnLoad.call(this, params)}}}
})// native
const nativePage = Page
Page = function (options: Parameters[0]) {if (options.onLoad && typeof options.onLoad === 'function') {const originalOnLoad = options.onLoadoptions.onLoad = async function (params: Record) {await ref.promiseoriginalOnLoad.call(this, params)}}nativePage(options)
} 

思路其实都差不多。

增强

上述的方法,虽然达到了目的,但是实在太简陋了,扩展性也很差。

我们以 ref.js 为例,里面只放了一个 promise 太浪费了,为什么不把它放入全局状态里去呢?这样随时可以取出来进行观察。

为什么不创建多个 Promise queue 呢? 这样还能循环往复地利用不同的队列,来作为代码执行的信道,同时又能够自定义并发度,超时,执行事件间隔等等。p-queue 就是不错的选择。

当然,这些也只是抛砖引玉,这些相信大家各自有各自的看法,反正先做到满足当前的需求,再根据进阶的需求进行适当的改造,做出来的才是最适合自己的。

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...