js防抖与节流

103 阅读3分钟

在前端开发中,有时候一些事件会因为触发过于频繁而导致的性能问题。当前事件还没有处理完,下一个相同的事件又被触发,严重的情况下会导致出现延迟、页面卡顿甚至崩溃。下面介绍两种解决这种问题的方法:防抖与节流。

防抖

使用一个setTimeout定时器来对需要优化的函数进行延迟执行。让事件在某个延迟的时间内只执行一次。

具体思路

  1. 事件在第一次触发时,先延迟时间N
  2. 如果在N内没有重复触发该事件,那么直接执行该事件。
  3. 如果在N内重复触发了该事件,那么将该定时器清零,重新开始计时。
//防抖函数
function debounce(fn, delay) {
    let timer = null;
  return function(...args) {
    if (timer) {
        clearTimeout(timer);
    }
    timer = setTimeout(()=>{
        fn.apply(this,args);
    },delay);
  }
}
function handle(){
    console.log("执行事件");
}
//滚动事件
window.addEventListener('scroll',debounce(handle,500));

节流

规定一定时间内只能触发一次事件处理函数。即使函数在短时间内被触发多次,也只能有一次生效。

实现方法

主要三种实现方法:时间戳,定时器,时间戳+定时器

时间戳

在第一次触发事件时记录下当前的时间,并且执行一次回调函数。然后,在这之后函数每隔N时间执行一次,在小于N时,该事件是不执行的,分别以当前时间和上一个 事件执行的时间进行时间差的对比。

//节流函数(时间戳)
var throttle = function (fn, delay) {
    var prev = Dta.now();
  return function () {
    var context = this;
    var args = arguments;
    var now = Data.now();
    if(now - prev >= delay) {
        fn.apply(context,args);
      prev = Data.now();
    }
  }
}
function handle(){
    console.log("执行事件");
}
// 滚动事件
window.addEventListener('scroll',throttle(handle. 500));

定时器

在触发事件时,设置一个定时器,当再次触发该事件时,如果定时器存在则会不执行,只有到延时的N时间后,定时器才会执行该函数,同时执行之后清空定时器,等待下一个流程进行循环。

var throttle = function (fn, delay) {
    var timer = null;
  return function () {
    var context = this;
    var args =  arguments;
    if(!timer) {
        timer = setTimerout(()=>{
        fn.apply(context, args);\
        timer = null;
      },delay);
    }
  }
}
function handle() {
    console.log("执行事件");
}
window.addEventListener('scroll', throttle(handle,500));

时间戳+定时器

在节流函数内部记录开始时间(startTime),当前时间(curTime)和剩余时间(remaining),当剩余时间小于等于0时则可以执行处理函数,可以保证第一次触发函数就可以立即执行,并且之后每隔N时间执行一次。 如果还没有到时间,则会在剩余时间后触发,保证最后一次触发时间也可以执行函数。 如果在剩余时间内再次触发事件,取消当前的定时器,并重新计算一个剩余时间来判断当前的状态。

var throttle = function (fn, delay) {
    var timer = null;
  var startTime = Date.now();
  return function (){
    var curTime = Date.now();
    var remaining = delay - (curTime - startTime);
    var context = this;
    var args = arguments;
    clearTimeout(timer);
    if(remaining <= 0) {
        fn.apply(context, args);
      startTime = Date.now();
    } else {
        timer = setTimeout(fn, remaining);
    }
  }
}
function handle(){
    console.log("执行事件");
}
window.addEventListener('scroll', throttle(handle, 500));