咱们常常须要监听滚动条滚动或者鼠标的移动,但浏览器触发这类事件的频率很是高,可能在10几毫秒就触发一次,若是咱们处理事件的函数须要操做大范围的DOM,这对于浏览器的性能是个考验,可能像chrome浏览器这样优秀的浏览器会好一点,但放到老版本的IE下,就可能发生卡顿现象。有的时候,咱们只须要处理函数执行一次,好比文本输入验证,执行屡次处理函数反而没有必要。javascript
因此咱们得想个办法,减小DOM操做的频度,也就是说稀释处理函数的执行频率,解决方法就是函数防抖和函数分流。函数防抖表示只执行一次处理函数,函数分流指下降处理函数的执行频率,下面是具体解释。java
函数防抖指的是屡次触发事件后,事件处理函数只执行一次,并且是在事件触发操做中止的时候。具体的思路就是延迟处理函数,若是设定的时间到来以前,又一次触发了事件,就清除上一次的定时器,具体代码实现以下。git
var obj = document.getElementById('handle'); /** * 事件触发的操做 */ function myFun() { console.log('throttleV1'); } /** * 不封装的方法 */ obj.onmousemove = function () { clearTimeout(myFun.timer); myFun.timer = setTimeout(myFun,50); }
这里有一个保存timer的技巧,若是不保存timer,那么执行完事件处理函数后,timer将被销毁,咱们也就没法再清楚定时器了,因此须要保存这个变量,即便它所在的函数做用域对应的函数已经执行完了。这里用到的技巧是把timer设置为外部函数的属性,这样就不会被销毁了。
咱们还能够对这个方法进行封装。github
/** * 封装的方法之帮顶函数 * @param method * @param delay * @param context */ function debounce(method, delay, context) { clearTimeout(method.timer); method.timer = setTimeout(function () { method.call(context); },delay); } obj.onmousemove = function () { debounce(myFun,50); };
这里涉及到了保存timer的技巧,总共有两个方法。web
/** * 封装的方法之闭包 * 闭包 若是想让一个函数执行完后,函数内的某个变量(timer)仍旧保留,就可使用闭包 * 把要保存的变量在父做用域声明,其余的语句放到子做用域里,而且做为一个function返回 * 因此闭包能够理解为分离变量 */ function debounce(method,delay) { var timer=null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { method.apply(context,args); },delay); } } obj.onmousemove = debounce(myFun,50);
函数分流的思想就是计时,上面的代码是只有在操做结束后才执行,只须要在上面的代码上加一个计时判断,若是超过了设定的时间,就执行一次处理函数,就达到了分流的效果。chrome
/** * 函数节流throttle * @param 事件触发的操做 * @param 延迟执行函数的时间 * @param 超过多长时间必须执行一次函数 * @returns {Function} */ function throttle(method, delay, mustRunDelay) { var timer = null, args = arguments; var start = 0, now = 0; return function () { var context = this; now= Date.now(); if(!start){ start = now; } if(now - start >= mustRunDelay){ method.apply(context, args); start = Date.now(); }else { clearTimeout(timer); timer = setTimeout(function () { method.apply(context, args); }, delay); } } } obj.onmousemove = throttle(myFun, 50, 500);
函数防抖和函数分流的思想都是经过定时器控制函数的执行频率。浏览器
http://www.alloyteam.com/2012/11/javascript-throttle/
http://web.jobbole.com/88306/
https://github.com/hanzichi/underscore-analysis/issues/21
https://github.com/hanzichi/underscore-analysis/issues/22闭包