在实际开发中,函数必定是最实用最频繁的一部分,不管是以函数为核心的函数式编程,仍是更多人选择的面向对象式的编程,都会有函数的身影,因此对函数进行深刻的研究是很是有必要的。javascript
比较直白的说,函数节流就是强制规定一个函数在一段时间内可以被执行的最大次数,好比,规定某个函数在每100毫秒的时间段内,最多被执行一次,那么对应的在10s(10000ms)内,最多就会执行100(10000ms/100ms)次css
这里节流和防抖的概念比较容易搞混,因此文中许多关键性定义,参考此处文档翻译过来,移步到the-difference-between-throttling-and-debouncinghtml
在浏览器中,频繁的DOM操做很是消耗内存和CPU时间,好比监听了resize,touchmove,scroll...等事件,在dom改变时都会不断触发回调。如今的react 和 vue 等前端框架都提出了虚拟DOM的概念,会把屡次DOM操做合并到一次真实操做中,就是使用了Diff算法,这样就大大减低了DOM操做的频次。可是,这里并非要讨论diff算法,若是感兴趣能够戳上面的连接,而是解释如何利用setTimeout
来减低DOM频繁操做的风险。前端
最先接触到这个概念的时候,是在《高程3》最后几章上面。vue
函数节流背后的基本思想是指,某些代码不能够在没有间断的状况下连续重复执行.第一次调用函数,建立了一个定时器,在指定的时间间隔以后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另外一个。
封装方法也比较简单,书中对此问题也进行了处理:java
function throttle(method,context) { clearTimeout(method.tId); method.tId = setTimeout(function(){ method.call(context) },1000) }
使用定时器,让函数延迟1秒后执行,在此1秒内,而后throttle函数再次被调用,则删除上次的定时器,取消上次调用的队列任务,从新设置定时器。这样就能够保证1秒内函数只会被触发一次,达到了函数节流的目的react
能够利用 resize
事件测试一下;git
var i = 0; function handler(){ console.log(i++); } window.onresize = function(){ throttle(handler,window) }
能够发现,在浏览器的调试模式下,切换横屏/竖屏,只触发了一次github
函数防抖 规定函数再次执行须要知足两个条件:ajax
好比:对一个函数加了100ms的防抖操做,而后在3s(3000ms)时间段内,这个函数被不连续的调用了1000次,3s后中止调用。 它只会在3100ms的时刻执行一次。
具体实现代码,看下 underscore.js中的 _.debounce 源码:
// Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function() { var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
wait
参数表明debounce
时间, _.now()
返回当前时间的时间戳,一样以ms 为单位。 若是传入了 immediate
,会当即触发回调函数。
应用场景:
参考资料: