收藏
评论

小程序切换后台后,不再使用 setData官方


你好,我是李艺。

上节课我们主要学习了如何使用串发复合命令延迟调用代码,这节课学习一个小技巧,就是在小程序切换至后台以后关闭对setData的一个调用。

首先我们看一个问题,前面我们在了解小程序的启动流程的时候已经知道了启动有两种一种是冷启动,一种是热启动,当小程序进入后台状态的时候,这个时候会有5秒的一个暂停状态,在这个状态里面小程序的代码仍然是可以运行的,如果5秒内小程序没有被唤起,这个时候它就会进入一种挂起状态,在挂起状态中小程序的JS代码不会运行,在后台状态里面小程序已经不可见,此时所有的与视图有关的代码,像setData的一个调用已经没有必要进行执行了,下面我们看项目实践。


首先看实践一,监听App进入后台的一个事件。

在这个小程序里面使用wx.onAppHide可以监听小程序进入后台的事件,或者是我们在App的周期函数里面,在它的onHide周期函数里面也可以捕捉小程序进入后台的一个时机,这个时候就可以停止页面里面对所有的setData的一个操作了。为了方便控制这个页面对象里面的setData方法,我们需要劫持Page对象,怎么样去劫持,首先需要在library目录下面创建一个page.js文件,在这个文件里面劫持onLoad和setData方法,因为setData方法只有在运行的时候才可以拿到引用,所以在这个地方先劫持onLoad的方法,然后在onLoad的方法里面再获得setData方法的一个引用,接着再往下需要在app.js文件里面调用并应用page.js的代码,使其劫持发生作用,最后在首页的onReady这个方法里面可以写一个定时器,不断地去调用setData去测试我们新编写的功能,在测试区的里面AppData面板里面,我们可以看到data数据属性它一直都在变化,在模拟器里面模拟单击Home键可以使小程序处于一种后台的状态,此时setData就不再更新了,AppData面板里面的数据也不再变化了。

接下来我们看实践一的代码演示。

要完成对setData方法的一个劫持,我们需要对我们当前的页面对象也是page进行一个改写,怎么样去改写,先看一下我们最终源码,在library下面有一个page.js文件,这是我们接下来要编写的一个文件,我们将这个文件先拷贝一下放到我们目前的项目下面,也放在同样的目录下 library下面,我们看一下这个代码主要是干了什么事情。

第一步首先是我们有一个常量的赋值,需要将我们原本的小程序本身,它原生的Page对象要做一个引用的一个保存,稍后因为这个地方我们可能还要用到,然后接下来我们会导出,有一个方法的导出,在这个里边,首先要从我们的options,options其实是我们这个页面里面我们自己设置的一些信息,包括data对象还有这些方法都在这个对象里面,然后我们要取到onLoad这个方法以后,接下来我们就开始重写这个方法了。

重写方法以后我们可以看到在这个地方,我们拿到了这个setData的一个引用,它是从this对象里面进行一个解构赋值,然后拿到这样一个引用的,在这个地方this其实就是我们当前的页面对象的一个实例,因为在这个地方它这个代码已经运行了,指的就是它的一个实例,再往下我们重新定义了setData的方法了,然后value是它的一个值,在这个地方我们看一下,我们用到了一个全局的状态就是global.state,现在是我们自定义的,现在它还没有值或者说它默认的它是undefined,在这个地方我们要检查,如果是这个状态等于hide,也就是它切到后台状态,非后台状态 这个地方有一个非的判断对吧,我们就调用setData方法对不对,如果是切到这个后台状态,那就是把我们这个调用给它忽略掉,这就是它的一个方法,这个地方有对于我们原来的方法就是一个再调用,我们把现在的方法放在前面执行,再执行具体的页面里边的自定义的那些代码逻辑,这就是我们整个的文件它的主要的一个代码,大概是这样的一个实现。

接下来我们看怎么样去应用这样的一个文件,首先看我们app.js里面,在这个地方有一个引入,我们将这个代码拷贝一下放在我们的app.js文件里面,放在这个页面的顶部 放在这个位置,这个地方我们看一下,当前其实它相当于是对我们当前的上下文执行环境里面的Page类型 类对象进行了一个重写,这个写法跟我们原来的普遍的一个写法有点不太一样,加载完成要取到default,然后将导出来的新的类对象然后赋值给它,这就完成了一个劫持,这个劫持完成以后为了测试效果,我们还需要写一个测试代码。

看一下我们这个里边是不是有一个叫做定时器,在这个地方有一个定时器,这个代码我们写到了onReady周期函数里面,找到首页,再找到它的onReady周期函数然后切到这个地方,这个代码稍后我们会删除,所以暂时就放在这个地方,然后这个里面我们做了一个什么事情,每隔500毫秒去设置当前这个页面上的一个名称,为xxx的这样的一个数据属性,当然这个数据属性在我们目前这个页面上它不存在也没有关系,不存在的话我们设置之后它会自动地去新增的,这地方设置这个方法调用就是setData(AppData),因为我们现在对setData有劫持,稍后我们再切换到后台的时候可以看到它会发挥作用,这个代码搞完了。

接下来我们开始在微信开发者工具里面进行测试,单击编译看它的一个表现,已经启动了,调试区没有错误,现在我们看一下AppData面板。看这个 这有一个三个x,有个数据属性,然后它后面这个值一直都在变化,它为啥会变化,因为我们里面有一个定时器500毫秒一个定时器,然后不断对它进行修改,所以它这个地方一直会变。现在我们在模拟器里面,我们选的这个地方有一个菜单,然后选择模拟操作里面有一个我们选择Home,当我们按下Home的时候,其实相当于在手机上按下Home键,这个时候小程序它会切到后台的状态,我们选这个不太明显对吧,重启了一下,我们刚才点了重启的按钮现在已经重新启动了,那么单击完以后这个不要去选了,因为它选了以后它又回到了那个状态。

项目在重启以后,我们看到我们小程序在切到后台状态以后,从我们AppData面板里面我们一直都可以看到三个x的数据属性一直都在变化,可以现在再打开模拟操作 选择Home,当这个面板浮现的时候其实已经代表无论我们接下来选哪一个,其实已经代表我们小程序已经进入一个后台状态了,但是此时我们看到AppData面板里面它这个数据属性仍然在发生改变,为什么仍然在发生改变,为啥发生改变,因为我们先前页面劫持里边用到了一个全局的数据属global.state对吧,现在global.state我们还没有设置,肯定它们不能发挥作用,所以接下来我们要在我们的AppData里面要添加程序的周期函数,然后去设置全局属性。

看一下我们最终的源码,找到app.js,在这个里边有两个方法在这里,一个是onShow,另外一个是onHide,下面这个是onUnhandledRejection,这个是什么意思呢,我们在用了Promise编程方式以后,它有一些没有捕捉到的一些reject的异常,我们可以捕捉以后在这个地方进行打印,这是它的一个作用,所以这三个方法我们都可以给它拷贝过来放在我们目前的项目里面,找到app.js放在下面 最下面就可以了,所有的周期函数我们都往下放 这样就可以了,这个代码修改完了

我们再次刷新项目看一下它的运行效果,现在我们看到这个数据属性一直在发生变化,这个时候我们单击模拟操作,然后选择Home,我们看到这个数据属性现在不在变化了,同时在这个地方,我们可以看到这个地方 setData没有作用,这个打印是在哪里打印的,就在我们劫持代码里面对不对,当我们选择一个入口方式以后,我们这个代码又开始恢复调用了,这个时候我们可以看到它定时器又起作用了,这样我们就实现了,对我们的所有页面里面的一个setData方法的自动的一个劫持,只要我们这个程序进入后台状态,无论是哪个页面里边对setData的一个调用都已经受到了我们的管制了,最后我们将我们的测试代码给它注掉。因为本身我们这个程序不需要这个测试代码,这个代码演示就到这里。


最后我们总结一下,我们想实现对setData方法的一个劫持,除了劫持原生的Page类对象以外,我们还可以定义一个工具函数 例如叫mySetData,在原来所有调用setData的地方改为调用mySetData,但是这种方式它比较繁杂,一般我们不这样采用对于原生的类对象的劫持,我们在使用的时候一定要克制,如果必须要发生劫持的话一定要把劫持代码统一放在程序的入口处,这样方便我们项目的其他维护者看到,如果是默默劫持了原生的类对象 而不加说明,这可能会给其他人 这个代码带来一些问题,导致他们的代码出错,这不是一个优雅的程序员所为。这节课我们就讲到这里,上面我们现在看到的这些网址是我们本节课涉及到的一些文档地址。

点击查看开放文档:


这节课我们主要学习了如何劫持Page类对象以及如何在小程序进入后台状态的时候,不再真正的调用setData方法,下节课学习如何实现数据预拉取与周期性更新。

最后我们说一下思考题。这里有一个问题请你思考一下,在第一课我们讲启动流程的时候我们曾经介绍过微信特意为开发者提供了数据预拉取和周期性数据拉取的这样一种优化机制,对于一些大块量的这些数据,我们不需要开发者自己拉取了,微信可以代为拉取,拉取以后再将得到的数据再提供小程序直接使用,这种贴心的机制你知道它怎么使用吗?这个问题先留给你思考一下,下节课我们一起深入探讨一下这个问题。

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

1 个评论

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

    `为什么App.js里面,给Page重新赋值就相当于重写了Page类型呢?对这行声明导致Page对象被劫持不理解。

    2022-11-02
    赞同
    回复 1
    • Mr.Black
      Mr.Black
      2023-03-08
      你可以看一下代码,`Page = require("./library/page.js").default`,这里没有使用let声明局部变量,其实将变量Page变量提升到全局,覆盖掉了全局的Page变量。
      2023-03-08
      回复
登录 后发表内容

小程序性能优化实践

课程标签