鼠标的mousemove、scroll,浏览器窗口的resize事件等,都是在短时间内重复触发。以onresize事件为例,若事件处理程序需要进行修改元素宽度高度等操作,那么频繁的触发事件会导致频繁的重绘页面。
DOM操作比非DOM交互需要更多的内存和CPU时间,连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时候甚至会崩溃。为了解决这个问题,需要使用定时器对该函数进行节流。
函数节流背后的基本思想是:某些代码不可以在没有间断的情况下连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码,当第二次调用函数时,它会清除前一次的定时器并设置另一个。如果前一次的定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换成一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。
throttle()函数:自动地进行定时器的设置和清除。接收两个参数:要执行的函数和在哪个作用域执行。throttle()首先清除之前设置的任何定时器,定时器ID是存储在函数的tID属性中的,第一次把方法传递给throttle()函数的时候,这个属性可能并不存在。接下来,创建一个新的定时器,并将其ID存储在方法的tID属性中。如果这是第一次对这个方法调用throttle()的话,那么这段代码就会创建该属性。定时器代码使用call()来确保方法在适当的环境中执行。如果没有给出第二个参数,那么就在全局作用域内执行该方法。
function throttle(method, context) {
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.call(context);
},500);
}
时间间隔设为500ms,这表示监听鼠标的mousemove、scroll,浏览器窗口的resize等事件,事件处理函数会连续调用多次,但只在最后一次触发该事件。
eg:
n=0;
window.onresize = function() {
console.log(n);
n++;
};
问题:简单的一次改变窗口大小就会导致函数不停地被调用,直到窗口大小不再变化。
解决:利用定时器,让函数执行延迟500毫秒,在500毫秒内如果有函数又被调用则删除上一次调用,这次调用500毫秒后执行,如此往复。
n=0;
function resizeHandler() {
console.log(n);
n++;
}
function throttle(method, context) {
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.call(context);
},500);
}
window.onresize = function(){
throttle(resizeHandler, window); // 或throttle(resizeHandler);