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);
}
相關文章
相關標籤/搜索