页面在绑定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作了实现和封装, 有兴趣能够去查看源码。