iView之Select组件的优化

iViewSelect组件在性能上的优化

    咱们公司的组件库是基于iView 比较早的版本修改后的仅供公司内部使用的组件库,所以在使用的过程当中就会遇到一些问题。接下来本文会对比Select组件在性能上作出的优化。javascript

Debounce函数

    咱们先来回顾一下debounce函数的使用场景:在前端页面咱们会遇到一些频繁触发的事件;好比前端

鼠标的移动 mousemove事件;

window对象的resizescroll事件;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更新后只会执行一次
有了这些知识的准备咱们就能够来谈谈使用这个组件遇到的性能问题了。函数

低版本iviewSelect组件遇到的问题

    在使用低版本的组件过程当中,当数据量很大例如某个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);
}
相关文章
相关标签/搜索