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); }