手写防抖、节流

1,000 阅读2分钟

防抖

概念:防抖是触发高频事件后,n秒内函数只会执行一次, 如果n秒内高频事件再次触发,则会重新计算时间.

使用场景:

  1. 搜索框输入查询
  2. 表单验证
  3. 按钮提交事件
  4. 浏览器滚动事件onscroll触发
  5. 浏览器窗口缩放, resize事件

节流

概念:节流指当高频事件触发时,稀释函数的执行频率,让其只会在n秒内执行一次.

使用场景:

  1. DOM元素的拖拽功能实现
  2. 射击游戏
  3. 计算鼠标移动的距离
  4. 监听scroll事件
防抖: 
//scroll方法中的do somthing至少间隔500毫秒执行一次 
window.addEventListener('scroll',function(){
    var timer;//使用闭包,缓存变量
    return function(){
        if(timer) clearTimeout(timer);
        timer = setTimeout(function(){
            console.log('do somthing')
        },500)
    }
}());//此处()作用 - 立即调用return后面函数,形成闭包

// 写法2
function debounce(fn, delay) {
  // 利用闭包保存定时器
  let timer = null;
  return function() {
    let context = this;
    let arg = arguments;
    // 在规定时间内再次触发会先清除定时器后再重设定时器
    clearTimeout(timer)
    // 重新设置一个新的延时器
    timer = setTimeout(() => {
      fn.apply(context, arg)
    }, delay);
  }
}
function fn() {
  console.log('防抖');
}
addEventListener('scroll',debounce(fn, 1000))

// 写法3
function debounce(fn) {
     let timeout = null; // 创建一个标记用来存放定时器的返回值
     return function () {
       clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
       timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
         fn.apply(this);
       }, 500);
     };
}

节流:
//scroll方法中当间隔时间大于2s,do somthing执行一次
window.addEventListener('scroll',function(){
    var timer ;//使用闭包,缓存变量
    var startTime = new Date();
    return function(){
        var curTime = new Date();
        if(curTime - startTime >= 2000){
            timer = setTimeout(function(){
                console.log('do somthing')
            },500);
            startTime = curTime;
        }
    }
}());//此处()作用 - 立即调用return后面函数,形成闭包

// 写法2
function throttle(fn, delay) {
  // 记录上一次函数触发的时间
  let lastTime = Date.now();
  return function() {
    let context = this;
    // 记录当前函数触发的时间
    var nowTime = Date.now()
    // 当前时间减去上一次执行时间大于这个时间间隔才让他触发这个函数
    if (nowTime - lastTime >= delay) {
      // 绑定this 指向
      fn.apply(context, arg);
      // 同步时间
      lastTime = Date.now();
    }
  }
}
function fn() {
  console.log('节流');
}
addEventListener('scroll',throttle(fn, 1000))

// 写法3
function throttle(fn){
  let flag = true;
  return function(){//-通过闭包来保存一个标记-
     if(!flag) return;
     flag = false;
     fn.apply(this);
     setTimeout(()=>{
      flag = true
    },500)
  }
}