收藏
评论

使用串发命令模式延迟同步请求(上)官方


你好,我是李艺。

上节课我们主要学习了如何将前端计算工作后移,这节课我们学习如何使用数据缓存。

下面我们看一下问题,一般情况下wx API以Sync结尾的接口是同步接口,例如像wx.getSystemInfoSync还有wx.setStorageSync,这些接口都属于同步接口,反之不以Sync结尾的接口都是异步接口,由于历史原因,有些接口虽然名称上它由Sync结尾,但实际上却仍然是同步接口,例如像那个wx.getSystemInfo还有这个wx.getStorage以及wx.setStorage这三个接口在开发里面还经常用到,而且经常是在App.onLaunch还有Page.onLoad,这些周期函数里面用到的,这对启动性能其实它是十分有影响的,小程序的启动流程是不能有任何人为的同步代码阻塞主线程的,如果需要拉取这些系统信息的话,在优化的时候我们可以由分接口代替,我们看一下都有哪些分接口。

例如第一个getSystemSetting接口是获取设备信息,还有像getAppAuthorizeSetting接口是获取微信APP授权信息 授权设置信息,再往下是getDeviceInfo是获取设备基础信息,第四个是getWindowInfo是获取窗口信息,最后一个是getAppBaseInfo是获取微信APP的一个基础信息,这里的每一个分接口它返回的信息都不一样,需要什么信息我们就调用什么样的信息的一个分接口就可以了。

还有在小程序启动过程中,我们尽量先使用默认参数在启动完成以后,也就是在Page.onReady这个事件派发以后再进行相关接口的一个调用,对于缓存后端接口数据的本地缓存存取代码,如果没有必要的话也要尽量放在启动流程完成以后,也就是Page.onReady这个事件派发以后再去调用,这里有一点我们需要注意,就是小程序现在它有一个接口叫做wx.getSystemInfoAsync,注意这个里面多了一个A ,这是一个不多见的以Async结尾的这样一个接口,它是一个异步接口,可以异步拉取这个系统信息,不阻塞主线程,但是这个接口需要一定的微信客户端版本支持,如果不在受支持的客户端上面使用、调用的时候,它会自动地又用原来的同步接口进行代替,这是我们要注意的,下面我们看项目实践。


首先看实践一,创建SystemInfoManager模块使用串发命令模式延迟同步请求。

目前在我们的app.js文件里面,在它的App.onLaunch这个周期函数里面有对wx.getSystemInfo接口的调用,这个代码是同步的,它会阻塞我们小程序启动流程的主线程的一个执行,我们必须将它进行改写,可以在globalData里面先定义默认参数,在启动的时候拿这些默认参数先给程序使用,然后在Page.onReady这个事件派发以后再拉取实际需要的这些数据。

下面在改造过程中我们将创建一个SystemInfoManager模块,用这个模块专门用于处理系统信息的一个拉取,目前我们需要的系统信息是比较有限的,可以先实现一些基础的代码,后续如果还需要其他的一些系统信息可以再逐步进行扩展,接下来就是使用串发复合指令对象延迟执行系统信息的一个拉取,这部分代码我们要放在app.js文件里面,这个代码量可能会稍微有一点点多,但是这个代码的逻辑还是比较清晰的。我们先在globalData上面设置默认的全局信息,然后再创建串发的复合命令对象 创建完成以后将它进行执行,那么我们什么时候让串发命令对象开始执行,可以在首页的JS文件里面,它的onReady周期函数里面设置命令的一个启动,这样关于系统信息的拉取操作,它其实就是在首屏渲染完成以后才开始执行的,这样一种设置其实不影响我们小程序整体的启动,串发复合命令的对象它有一个特点,就是前面的子命令完成以后后面的子命令它才会开始执行,我们利用这个特点就可以延迟这系统信息的一个拉取了。

在这里有一个问题请你思考一下,为什么我们要把拉取系统信息的主要代码要写在app.js文件里面的onLaunch周期函数里面?因为globalData它是在这里定义的这段代码的一个主要作用,为了拉取 往globalData对象里面存储的这些信息,那么将这些代码放在这里是最合适的了,面向对象模拟真实世界的事物关系,它使得我们软件设计有规可依,但是面向对象它有一个缺陷就是容易将相互联系在一起的代码人为地给它隔离开,这种情况下 我们利用这种串发的复合命令对象就可以巧妙地弥补缺陷,下面我们看代码演示。


首先打开我们微信小游戏这个项目,在开始改造之前我们先看一下我们目前的项目在执行的时候,它这个信息是如何获取的,重启一下我们这个项目,注意看一下我们调试区,这个地方有一个打印 已取到系统消息,这个信息我们是在哪里打印的呢,是在app.js里面对不对,我们打开代码看一眼,现在开发者工具因为我同时开了录屏的原因,它启动以及运行变得非常的一个卡顿,其实如果把录屏关了以后,它运行效果还是可以的,我们看一下这个代码里面,这个地方有个打印已取到系统消息了,这是我们在调用getSystemInfo接口以后,就是我们拿到这个系统消息以后打印的一个信息,然后注意一下我们这个信息打印,它其实是在哪里,在index onready之前,它其实在它的前面打印的,也就是说我们的首页渲染还没有完成,这个系统消息已经拉取了对不对,当然这个代码它是同步的,它会阻塞我们整体的一个流程的进行,所以我们需要将它进行优化。

优化的第一步,首先我们要创建一个SystemInfoManager,这样的一个管理器模块,管理器模块我们要放在我们的library manager放在这个下面,这个下面还没有,但是我们可以去我们的最终源码里面看一下,因为那个地方肯定有已经写好的代码对不对,6.5.1找到miniprogram,然后library manager,这个文件就是我们需要的文件 将它拷贝一下放到我们目前的目录下面,library然后manager放在下面。

现在我们看一下我们这个代码主要是做了什么事情,首先是引入它,因为我们接下来有相关接口的调用需要用到这个工具方法,这是一个类 SystemInfoManager,然后在下面我们有个导出,其实直接导出的是它的一个实例,它实例化的一个实例,本身这个模块在我们程序里面可以说是单例的,在主线程里面它是唯一的,在这个里面有一个很重要的方法就是retrieveSystemInfo,一上来我们会判断一下是不是可以调用这样的一个接口,这个接口,先前我们提到了它其实是一个什么样的接口,一个特殊的异步接口对不对,getSystemInfoAsync,很少有接口这个里面是加A的,一般都是加Sync后面的后缀,看它能不能用,如果能用我们就用它,如果不可以我们就用后面getSystemInfo进行调用,进行调用完以后拿到这个结果,这个地方拿到结果以后,在这个地方我们不能直接用这样的一种方式,就是wx.getSystemInfoSync等于它 这样是不可以的,这个代码我们是想重写接口的一个实现,让这个接口直接返回,我们已经取到的信息不需要重复地去拉取了,当然这样不可以的话可以变通一种方式,用Object的里面的一个defineProperty,用这样的一个接口,这个是JS的方法,JS对象的一个方法用于我们在一个对象上,定义它的属性,我们用这个,然后同时将后面的参数给它置为true,把它value写成一个箭头函数让它返回,这样就可以了,这个方法执行完成以后,我们这个信息就拉取到了,拉取到了以后我们再调用这个方法,就是getSystemInfoSync 再调用它的话其实它已经不是一个同步接口了,它其实就相当于调箭头函数,然后直接把已经拿到的本地的信息给它取出来,再取出它的statusBarHeight就是状态栏的高度,这个高度我们在代码里面会用到,还有屏幕的分辨率也会用到,还有这个信息稍后也会用到,这就是它的简单的一个实现,管理器代码然后完成以后,接下来我们要去调用它。

首先我们要看一下app.js,app.js里面我们有哪些改造,在这个地方有一个按新方式拉取系统信息,这是我们的主要的一个代码,这个代码稍微有一点点长对吧,这个代码给它拷贝一下到这个地方拉取新的信息,这是我们原来代码 原来这个代码里面干了什么事情,拿到这个信息以后,我们设置了这个信息,还有是又调用它 拿到custom又设置这些信息对吧,还有这个信息,它设置了一系列的一个信息,这些信息可能是在接下来这个程序运行的时候需要用到的一些信息,将这个先给它注掉,然后将我们新代码给它放在这个地方来,看一下新代码。

首先一上来我们先设置这些,这个是我们默认配置,我们当前以什么样的一个屏幕大小进行测试的时候,我们就设置什么样的一个默认的信息,把这个信息给它设置上 设置完以后,我们这个程序就可以用这些默认的信息了,再往下是我们引入了三个模块,其中就包括我们新创建的 system_info_manager,引用它的实例,再往下这个地方我们有个ClosureCommand,ClosureCommand是我们的一个闭包指令对象,在这个里面,我们首先会这个地方注意,这有一个await,因为我们这个地方是async 这个地方是await,然后去调用它的retrieveSystemInfo,因为这个调用它会占用一些时间,所以它是同步的,会占用一些时间,取到以后会打印这些信息,已取到系统信息,在取到完成以后,我们这个地方看一下,这有一个statusBarHeight的一个获取,我们可以调这个接口拿到,还有custom 调用它里面的方法拿到,然后这个信息 就是这些信息包括这个信息其实就是我们原来的这些信息,它就是稍微修改一下用新的方式去设置了,这就是它的一个修改,我们现在不需要了把它删掉,这是在app.js里面所要做的一些修改。

接下来我们还要看在我们主页里面还有一个修改,主页里面还有修改,在index目录下面要找到我们的onReady周期函数,在这个地方允许异步拉取系统信息了,将这个给它拷贝一下到我们项目里面来 这里,放在这个地方 onReady完毕了,我们调用了asyncRetrieveSystemInfo,这个对象它的getCommand取到它的第一个子命令,然后markComplete标记它的完成,然后后续的子命令才可以执行,因为这个对象它本身是一个串发复合命令。

我们再确认一下我们这个里边,在app.js里面,我们来看一下它这个命令,其实在这个地方复制的 看到没有,等于它对不对,然后这个里面它的这个地方有一个new ClosureCommand,它虽然没有传任何代码,但是它也占据了一席之地,然后它的第二个子命令才是cmd,才是我们前面的这些,第一个子命令它不完成的话,第二个子命令它就不会执行,也就是我们上面这些代码就不会执行,然后它里面的同步调用它就不会占用时间,这样一来对我们启动 整体的小程序的启动它就没有影响了,而在我们主页里面,在这个页面首页 首屏渲染完成以后,把第一个指令然后设置完成了,设置完成以后,它这个复合对象就开始执行,第二个指令就开始执行,然后拉取系统信息代码也开始执行,这样的话就不影响了,代码改完了。

接下来我们打开我们微信开发者工具单击编译,看一下它的实际运行效果,注意看一下已取到了系统信息,看到没有,这有一条打印信息,现在信息的打印它已经在index onready,index onload,这两个信息打印在它的后面了 也就是说它现在要做的工作其实已经不再影响,我们小程序的一个正常启动了,代码演示就到这里。

最后一次编辑于  2022-07-14
赞 1
收藏

1 个评论

  • 清蒸鱼
    清蒸鱼
    2022-11-02

    ·同步方法为什么还要串发,同步转异步不是更好吗?

    2022-11-02
    赞同 1
    回复
登录 后发表内容

小程序性能优化实践

课程标签