Web性能优化-防抖与节流

1,567 阅读2分钟

前言

浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。

防抖

以用户拖拽改变窗口大小,触发 resize 事件为例,在这过程中窗口的大小一直在改变,所以如果我们在 resize 事件中绑定函数,这个函数将会一直触发,而这种情况大多数情况下是无意义的,还会造成资源的大量浪费。

这时候可以使用函数防抖来优化相关操作:

function debounce(fn, delay = 1000) {
    let timer;
    return function () {
        window.clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments);
            window.clearTimeout(timer);
        }, delay);
    }
}

// 进行函数防抖				
let debounced = debounce(function () {
    console.log('debounce');
});

// 监听resize事件				
window.addEventListener('resize', debounced);

先执行 debounce 函数,返回内部函数(实际调用的函数)。
每一次 resize 事件被触发,都会触发返回的内部函数并清除当前的 timer 然后重新设置定时器。
只有在结束触发 resize 事件时,才能在 delay 时间后执计时器内部函数fn。

示意图:

注:在事件触发过程中,只执行一次。

节流

希望连续执行的事件,不要触发一次就执行一次,这样做毫无节制,造成资源浪费。
应该做到相同间隔时间内执行,不要连续执行。如:根据scroll事件做的图片懒加载。

这时候可以使用函数节流来优化相关操作:

function throttle(fn, delay = 1000) {
    // 节流开关				
    let run = true;
    // 返回函数				
    return function () {
        if (!run) {
            return;
        }
        let timer = setTimeout(() => {
            fn.apply(this, arguments);
            window.clearTimeout(timer);
            run = true;
        }, delay);

        run = false;
    }
}

// 进行函数节流				
let throttled = throttle(function () {
    console.log('throttle');
});

// 监听scroll事件				
window.addEventListener('scroll', throttled);

先执行 throttle 函数,返回内部函数(实际调用的函数)
当窗口滚动时,scroll 事件持续触发,内部函数会根据节流开关在单位时间间隔内执行fn。

示意图:

注:在事件触发过程中,只在相同时间间隔内执行多次。