setData 调用优化
[视频] 你好,我是李艺。 上节课我们主要学习了脚本优化技巧,这节课学习set Data方法在调用时的优化技巧。 首先看一下问题,在第6.6讲我们介绍过,当小程序切换至后台以后,setData便不需要调用了,这样可以节省逻辑层与视图层之间的调用消耗,还可以节省页面的渲染消耗。除了这个优化点以外,结合小程序的双线程运行机制和重渲染机制,还有其他的一些优化技巧,这节课我们就一起来看一下。 首先看实践一。 不要多次分开调用setData,尽量要合并调用,在主页的JS文件里,在dealWithListData这个方法里有三处调用setData的代码,这个代码是可以优化的,三处调用显然可以合并为一处,在一个函数内,如果调用一次setData可以达到目的就不需要分开多次调用,甚至在不同的if else分支语句里边调用了setData,适当用一些编程技巧也可以在if语句外面合并成一次调用,如我们屏幕上展示的是优化后的JS的调用代码,小程序页面没有一个beforeRender周期函数,如果有的话,所有需要setData的数据在不同地方的一个数据更新倒可以积攒起来,在这个周期函数里面集中进行更新。 下面我们看代码演示。 首先我们在主页的JS文件里面找到dealWithListData这个方法,这个方法里面我们看一下,目前我们有:这是第一个setData的调用,然后下面还有一个setData,在后面这个地方也有一个setData,一共有三处setData的调用,这三处调用它都处于同样的一个函数体代码里面是可以合并的。首先我们将这个给它移下来,移到这个位置,然后后面这个调用也可以移上来,把它放在一起,这个就删掉,同样我们后面还有一个newList,newList它其实不涉及到数据更新,所以我们是可以直接进行一个赋值的,这个地方它不需要调用setData,newList目前在我们这个里面,它其实目前是在data数据对象里面,它也不需要在data数据对象里面,它可以直接放在我们的Page对象下面,这样的话可以减少对这个视图更新的一个触发,位置改完以后我们还需要将所有的对它的调用代码,进行统一的一个查找,我们可以查this.data.newList,这个地方this.data.newList改成this.newList,再看一下其他地方,已经没有了 这个地方已经可以了,改完以后我们重新单击一下编译按钮,这个page我们再看一下,目前我们page是已经在我们Page对象下面,是没有问题的。page目前直接这样赋值也是可以的,它也不涉及到数据的视图的一个更新,所以直接这样赋值也是没有问题的,它和下面的newList一样的,也是可以通过这样的方式更新,项目已经刷新了,我们现在看一下表现,看一下我们的调试区没有错误,说明我们变动是可以的,没有问题,这个代码演示我们就说到这里。 下面看实践二。 不准备渲染的数据不要放在data数据对象里边,在主页的JS文件里边数据allList表示所有列表数据,目前它位于data数据对象里面,如我们屏幕上所示,我们可以将它直接放在当前的页面对象下,直接放在当前的页面对象上,也可以通过this关键字直接进行取用,一般方法里面this它就是指代我们当前的页面对象。 下面我们进行代码演示。 首先我们要查一下当前的allList目前位于我们data数据对象里面,前面说过所有的只有需要触发视图更新的数据才需要放在data对象里面,不需要触发的,完全可以放在外面,这是不影响的,所以我们将这个给它拷贝出来,另外我们在这个页面里面查一下所有的this.data.allList查一下这个引用,将相关的代码给它修改一下,把中间的data给它去掉,这个地方也是给它去掉,已经没有了 所有的都修改过来了,然后我们再单击编译按钮进行测试,调试区没有问题,然后看页面的表现也没有问题,这个代码演示就到这里。 下面我们看实践三,通过index局部更新长列表数据。 下面我们尝试给项目添加一个新的功能,在单击列表中的列表项标题的时候,在标题文本的末尾就压一个字符,每单击一次就追加一次,这个需求要求在主页JS文件里面的onTapRecycleItem这个方法里面进行实现,在列表数据中的某一项数据发生变化的时候,没有必要更新整个数据列表,只需要使用计算属性、使用索引局部更新的方法,更新列表中对应的某一条数据就可以了,要实现局部更新,对recycle-view组件有两种方法:第一种方法是如我们屏幕上所展示的,先改变data数据,再使用forceUpdate方法进行更新,在示例源码里面,我们在调用setData方法改变标题文本的时候,展示的便是更新某一条数据的方法,对于recycle-view recycleList是它当前真正渲染的数据,但是仅仅更新这个数据还不能完成页面的更新,还需要额外调用渲染上下文对象的forceUpdate方法,才能强制长列表进行重新渲染,对于recycle-view组件还有另外一种更新某一个列表项标题的方法,直接调用长列表组件上下文渲染对象的update方法,这种方法更简单,如我们屏幕上现在展示的,在示例源码中,item是引用对象,修改它的字段以后不需要再做其他的任何更新了,只需要再调用一下长列表组件渲染上下文对象的update方法就可以了。 下面我们看代码演示。 首先打开我们的最终的源码,在主页的JS文件里面我们找到onTapRecycleItem这个方法,在这个方法里面注意前面已经拿到了相关的一些数据,首先第一步,我们要用forceUpdate这种方法进行更新,将这个代码给它拷贝一下,然后在我们目前的项目里面找到onTapRecycleItem这个方法,前面的数据已经拿到了。我们将新代码给它粘进来,把这些代码给它反注释,我们看一下这个地方是直接将item它title属性直接在尾部加了一个加号,当然其他字符也可以,然后我们再拿到这个id,这个id其实前面已经有了,所以这个地方不再需要了,把这个给它去掉。然后我们再拿到recycleList 这是一个数据,在这个数据里面我们要找到id它所对应的需要更新的列表项,找到它以后,然后在这个地方我们用了计算属性,然后去更改它的title数据,这个数据就是item.title,就是我们前面已经更改的数据设置为这样的一种数据结果,最后再调用这个forceUpdate它其实是一个ctx,ctx是我们当前的recycle-view组件的一个上下文渲染对象,其实是它,然后在它上面调用forceUpdate方法,这个代码已经写完了,我们单击编译测试一下 看它的一个表现,单击可以看到标题后面它每次单击都会添加一个加号,这是第一种更新的方式,下面我们看第二种方式,第二种方式是更简单,直接用update这种方法将前面给它先注掉,然后使用后面这种方法,首先是改变数据属性,然后加一个加号,后面我们就直接调用渲染上下文对象的update方法,同时将index也就是我们当前的列表项里面索引,然后传给它,第二个参数是我们要更新的数据,我们需要更新哪一项数据就把这个数据传给它就可以了,注意这个地方其实它的参数类型它是一个数组,我们再单击测试看一下表现,我们看到标题后面加号仍然可以正常的追加,也没有问题,这个代码演示我们就说到这里。 下面看实践四,创建examples/pages/index页面。 按索引更新data数据,在扩展示例页面里边如我们屏幕上展示的,我们需要实现单击某一个组,将其他的组自动折叠起来这样的一个效果,折叠与否是通过一个名称为open的子属性进行控制的,在对这个属性的改变过程当中,我们就可以使用索引法进行局部更新,主要的代码如屏幕上所展示的这样,其中这个open是准备更新的数据属性,然后需要更新的数据准备好以后,就可以使用索引法调用setData方法统一进行更新了,这种更新方式具有统一性,在任何项目里面都可以使用,因为这个页面里边包含的数据量不大,修改带来的正面效果可能很小,但它也展示了如何使用索引进行局部更新的方法,当数据量很大的时候,这种更新方式的优势会更加明显 下面我们看代码演示。 首先我们看一下当前的源码在examples/pages目录下面,找到index.js文件,在这里面有一个kindToggle,这是这个方法它在我们单击每一组的时候会触发的,我们可以在wxml这个标签文件里面看到,它是有一个type属性type事件进行触发的,触发以后在js里面我们先取到id,然后这地方有一个循环,它会循环列表的每一项,同时进行检查,如果是这一项的id与我们当前传进来id相同,那就把它的open属性进行一个切换,同时其他的我们给它置为false,最后我们再通过setData重新设置一下list数据,这种方式在我们list数据很小的情况下其实没有什么问题,也看不出什么差别来,但是如果我们list数据量很大,这种方式其实它是非常耗费资源的,下面我们看我们要优化的代码是怎么写的。 首先找到我们最终的源码,找到同样的文件,也是kindToggle这个方法。第一步我们要创建一个tempData这样的一个临时对象,接下来是我们对for循环的一个改造,在这个里面我们要在属性的设置这个地方,我们要加这样一个代码,把它放在它的前面,另外还有一个这个地方也有一个,把这个代码也给它放在这个地方前面。注意这个地方,我们在往tempData数据对象里面添加这个计算属性的时候为什么要加if判断,这两个判断它本质上是为了让我们少一点往tempData对象里面,加一些不需要更新的数据。如果原来本质上它open属性没有变化的话,我们就没有必要更新,这种情况下我们就不需要去设置了。只有当它属性有变化的时候我们才需要去往里写,tempData准备好了以后,接下来我们就调set。这是set方法,通过set方法去设置,我们设置数据,这个就不要了,这个地方我们可以看一眼,打印我们可以把它放开,稍后我们会看到它的内部的数据表现。 这是原来的代码,把它注掉,然后现在是改用这样的一种方式,这个文件测试的主页目前我们还没有一个入口,下面我们给它加一个小入口,找到examples,这是一个独立的分包,然后分包里面这是它的一个主页,找到我们的app.json,找到关于分包的设置,这个地方已经存在了,所以我们也不需要添加了,接下来我们只需要改编译模式,将我们这个测试主页作为启动页面进行测试,已经启动了,现在我们单击任意组,单击以后我们可以看到这个地方,首先这个界面上它已经发生了切换,然后我们可以看一下tempData的打印情况,在这个里面我们看一下它里面它写法,是list[1].open,这是它的一个属性名称,后面这个true是它的一个值,然后上面这个也是list[0].open等于false,这是它的,而且数据更新量非常小,只有这一条数据 它这个数据量是非常小的,这是关于按索引法局部更新数据对象的一种写法,我们直接这样写也可以,但是我们如果是照着我们这个代码里面刚才看到的这种方式,就这样一种方式这样去写可能会更加清晰一点,先创建一个临时对象,然后往临时对象里边去准备我们要更新的数据属性、准备要更新的数据,所有的都准备好以后再统一调用setData,然后进行一个设置,这就是局部更新的方法,这个代码演示我们就说到这里。 在使用setData更新数据列表的时候,优先选择计算属性进行局部更新,如果有两条以上的数据需要更新,可以并排写多条计算属性,这节课我们就讲到这里。 点击查看:recycle-view 上面的网址是本课涉及的文档地址。 这节课我们主要学习了有关setData调用相关的优化技巧,下节课我们学习网络请求相关的优化技巧。 最后看一下思考题,这里有个问题请你思考一下,我们知道小程序为了保证整体上所有程序的流畅运行限制了网络请求的并发数最大为10,如果同时请求数达到了这个数字wx.request的请求将无法继续发出,后来在小程序基础库版本1.40更新以后,将这个地方进行优化了,超出的请求它不再被直接拒绝,而是放入了一个队列中排队,稍后等设备资源允许了以后,它会重新发起,只要我们使用的小程序基础库版本大于1.40便不会有10个最大限制这个问题,这样一来貌似关于并发限制这个问题便不是问题了。但是这里仍然有另外的一个问题,程序里面的并发请求它们的优先级往往并不是一样的,例如对后端数据接口的调用这类请求的优先级往往都比较高,而对于打点 日志的接口调用这类请求的优先级就比较低,那么有没有办法在网络请求发出的时候就给请求操作安排一个优先级,让高优先级的网络请求先执行呢?下节课我们就一起来深入探讨一下这个问题。