iView
之Select
组件在性能上的优化 咱们公司的组件库是基于iView
比较早的版本修改后的仅供公司内部使用的组件库,所以在使用的过程当中就会遇到一些问题。接下来本文会对比Select
组件在性能上作出的优化。javascript
Debounce
函数 咱们先来回顾一下debounce
函数的使用场景:在前端页面咱们会遇到一些频繁触发的事件;好比前端
鼠标的移动mousemove
事件;
window
对象的resize
、scroll
事件;java
keydown
,keyup
事件;app
实际的使用过程当中咱们可能不须要每次触发事件的时候都去响应该事件,咱们每每须要当用户中止操做多少ms
后去响应事件。这个时候咱们就须要用到debounce
函数了。下面是一段debounce
函数iview
export function debounce(fn) { let waiting; return function() { if (waiting) return; waiting = true; const context = this, args = arguments; const later = function() { waiting = false; fn.apply(context, args); }; this.$nextTick(later); }; }
这段代码的意思的意思是当DOM更新后去响应这个事件,而且DOM更新后只会执行一次
有了这些知识的准备咱们就能够来谈谈使用这个组件遇到的性能问题了。函数
iview
Select组件遇到的问题 在使用低版本的组件过程当中,当数据量很大例如某个select
选择器里面有500条甚至更多的数据时,进行模糊搜索有可能卡死页面,关闭页面有延迟。性能
在Select
组件的mounted
钩子中有三个监听,分别是组件添加,删除,和选中时监听事件。在监听事件中会去遍历Select
当中的全部子组件作出相应的改变。测试
//监听子组件的移除 this.$on('remove',() => { if (!this.remote) { this.modelToQuery(); this.$nextTick(() => this.broadcastQuery('')); } else { this.findChild((child) => { child.updateSearchLabel(); // #1865 child.selected = this.multiple ? this.model.indexOf(child.value) > -1 : this.model === child.value; }); } this.slotChange(); this.updateOptions(true); })
查找这个监听的通知对象发现正是Select
的子组件在销毁或者是建立时通知父组件作出相应的变化。优化
//组件销毁时通知父组件 beforeDestroy () { this.dispatch('iSelect', 'remove'); this.$off('on-select-close', this.onSelectClose); this.$off('on-query-change',this.onQueryChange); }
那么问题就出在这里了,当有大量的子组件时,每个组件移除,父组件须要遍历一次。这样就拖累性能。this
既然前面提到debounce
函数,想必你们应该想到要怎么解决了。使用debounce
函数可以解决这个问题,咱们只须要全部子组件销毁时通知父组件一次就够了。引入debounce
函数后经本人测试基本上解决了卡顿以及卡死的问题,代码以下。
//select组件mounted函数当中去监听 append 、remove 事件 this.$on('append', this.debouncedAppendRemove()); this.$on('remove', this.debouncedAppendRemove()); //引入debounce函数 debouncedAppendRemove(){ return debounce(function(){ if (!this.remote) { this.modelToQuery(); this.$nextTick(() => this.broadcastQuery('')); } else { this.findChild((child) => { child.updateSearchLabel(); // #1865 child.selected = this.multiple ? this.model.indexOf(child.value) > -1 : this.model === child.value; }); } this.slotChange(); this.updateOptions(true); }); }
低版本中子组件的监听事件没有移除掉,高版本的有移除。
mounted () { this.$on('on-select-close', this.onSelectClose); this.$on('on-query-change',this.onQueryChange); } beforeDestroy () { this.$off('on-select-close', this.onSelectClose); this.$off('on-query-change',this.onQueryChange); }