之前写过但是不记得在哪了,今天同事要一个滑到页面底部加载更多内容的效果,又想起了这玩意儿,确实挺实用和常用的,谨此记之。
函数节流从字面上的意思就是节约函数的执行次数,其实现的主要思想是通过定时器阻断函数的连续执行,尤其适合用在频繁操作,比如window的resize和scroll事件等。
window的默认scroll事件间隔时间大概只有十几毫秒,如果频繁的scroll,然后去请求,然后渲染,对性能肯定有很大的影响。
大概模式:
var processor = { timer: null, performProcessing: function(){ // 要执行的代码 }, process: function(){ clearTimeout(this.timer); this.timer= setTimeout(function(){ processor.performProcessing(); }, 100); } }; //调用 processor.process();
performProcessing是要频繁执行的函数,每次process会把之前的定时器timer给清除掉。简单来说,就是performProcessing每次会延迟100ms执行,如果在这段时间内又被执行,每次都会把前面的给clear掉,保证100ms内只会执行一次。 impress通过闭包实现的函数节流:
function throttle(fn, delay) { var timer = null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); }; }
两种方法各有优劣,前一个封装函数的优势在把上下文变量当做函数参数,直接可以定制执行函数的this变量;后一个函数优势在于把延迟时间当做变量。
举个栗子:
Document
函数节流升级版
var throttleV2 = function(fn, delay, mustRunDelay){ var timer = null; var t_start; return function(){ var context = this, args = arguments, t_curr = +new Date(); clearTimeout(timer); if(!t_start){ t_start = t_curr; } if(t_curr - t_start >= mustRunDelay){ fn.apply(context, args); t_start = t_curr; } else { timer = setTimeout(function(){ fn.apply(context, args); }, delay); } }; }; window.onresize = throttleV2(myFunc, 50, 100);
升级版的作用是myFun间隔50ms执行一次,100ms内必须执行,因为有可能你在50ms内使劲执行myFun,这个时候timer会被clear掉,就会导致事件永远不会执行,这是比较极端的情况。