頁面在綁定resize,keydown或者mousemove這些能連續觸發的事件時,用戶只要很常規的操做,就能連續觸發屢次綁定的方法。當綁定方法裏面存在大量的相似於DOM操做這種極其消耗性能的代碼時,會直接致使頁面運行的卡頓。這個時候就會用到函數節流。javascript
函數節流最普通的實現就是經過取摩操做來過濾部分執行。參考代碼以下java
javascriptvar mousemoveCount = 0; function mousemoveListener(e){ mousemoveCount++; if(mousemoveCount % 2 === 0){ return; } console.info('業務邏輯'); }
當第一次觸發並執行mousemoveListener事件時,會打印「業務邏輯」;緊接着第二次執行mousemoveListener事件時,因爲mousemoveCount爲2,會直接return掉,並不會打印「業務邏輯」。這樣子,就實現了函數節流,存在複雜計算的業務邏輯運行次數減半了。函數
可是這種實現存在兩個問題:性能
因此就有了下面的優化實現(throttle和debounce)。優化
throttle又叫函數節流,思路是控制某一個時間段(執行週期)內觸發的事件,只會執行一次業務邏輯。代碼以下:code
javascriptvar lastMousemoveTime = 0, mousemoveTime = 100; function mousemoveListener(e){ var now = new Date().getTime(); if(now - lastMousemoveTime <= mousemoveTime) { return; } lastMousemoveTime = now; setTimeout(function(){ console.info('業務邏輯'); }, mousemoveTime); }
第一次觸發mousemove會設置100ms後執行業務邏輯,在這以後的100ms裏面觸發的mousemove都不會觸發業務邏輯。至關於控制了mousemove事件100ms觸發一次,也就是10幀。事件
使用這種實現(throttle),能夠作到觸發頻率可控。但當業務但願連續的觸發事件只在以後一次觸發後才執行業務邏輯,好比resize事件,只但願窗口變化結束後才進行業務邏輯的運行,throttle實現就不適用了。這個時候就須要使用到debounceip
debounce又叫函數去抖動,思路是業務邏輯在resize不在觸發後才執行。代碼以下:underscore
javascriptvar resizeTimer = null; function resizeListener(e){ if(resizeTimer) { clearTimerout(resizeTimer); } resizeTimer = setTimeout(function(){ console.info('業務邏輯'); }, 100); }
但resize連續快速觸發時,業務邏輯並不會執行。只有當最後一次觸發resize後100ms,才執行業務邏輯。這種狀況就能實現只在最後一次resize觸發業務計算了。get
underscore 中已經對throttle和debounce作了實現和封裝, 有興趣能夠去查看源碼。