函数防抖(debounce)的实现

2022 年 4 月 5 日 星期二(已编辑)
/
12
这篇文章上次修改于 2024 年 7 月 20 日 星期六,可能部分内容已经不适用,如有疑问可询问作者。

函数防抖(debounce)的实现

What is 防抖?

在事件触发n秒后再执行回调,如果在这n秒期间又被触发,则重新记时,也就是说在n秒之内只执行最后一次触发

执行过程

  • 当事件触发时,相应的函数不会立即触发,而是会等待一定的时间
  • 当事件密集触发时,函数的触发将会频繁重置延迟
  • 只有延迟时间内再无任何事件触发,才会执行真正的响应函数
a426833e5d485957c71ee7c5a7870856

a426833e5d485957c71ee7c5a7870856

应用场景

  • 输入框中频繁输入内容,搜索或提交信息
  • 频繁点击按钮,触发某个事件
  • 浏览器监听滚动事件完成某些操作
  • 用户缩放浏览器的resize事件

功能实现

基础实现

function debounce(func, delay) {
  //存储上一次触发的timer
  let timer = 0;
  return function (...args) {
    //清除上一次触发的timer
    timer ? clearTimeout(timer) : '';
    timer = setTimeout(() => {
      //绑定调用该函数上下文的this
      func.apply(this,args);
    }, delay);
  };
}

简易版实现了最基本的防抖函数

封装立即执行功能

function debounce(func, delay, immediate = false) {
  //存储上一次触发的timer
  let timer = 0;
  //
  let invoke = false;
  return function (...args) {
    //清除上一次触发的timer
    timer ? clearTimeout(timer) : '';
    //在触发延迟回调前只执行一次
    if (immediate && !invoke) {
      invoke = true;
      func.apply(this, args);
    } else {
      timer = setTimeout(() => {
        //触发回调后 再次初始化
        invoke = false;
        //绑定调用该函数上下文的this
        func.apply(this, args);
      }, delay);
    }
  };
}

封装取消功能

function debounce(func, delay, immediate = false) {
  //存储上一次触发的timer
  let timer = null;
  let invoke = false;
  return function _debounce(...args) {
    //清除上一次触发的timer
    timer ? clearTimeout(timer) : '';
    //在触发延迟回调前只执行一次
    if (immediate && !invoke) {
      invoke = true;
      func.apply(this, args);
    } else {
      timer = setTimeout(() => {
        //触发回调后 再次初始化
        invoke = false;
        //绑定调用该函数上下文的this
        func.apply(this, args);
      }, delay);
    }
  };
  //封装取消功能
  _debounce.cancel = function () {
    timer ? clearTimeout(timer) : '';
    timer = null;
    invoke = false;
  };
}

获取防抖函数返回值

  • 使用Promise
function debounce(func, delay, immediate = false) {
  //存储上一次触发的timer
  let timer = null;
  let invoke = false;
  return function _debounce(...args) {
    return new Promise((resolve, reject) => {
      //清除上一次触发的timer
      timer ? clearTimeout(timer) : '';
      //在触发延迟回调前只执行一次
      if (immediate && !invoke) {
        invoke = true;
        const result = func.apply(this, args);
        //使用resolve把返回值抛出
        resolve(result);
      } else {
        timer = setTimeout(() => {
          //触发回调后 再次初始化
          invoke = false;
          //绑定调用该函数上下文的this
          const result = func.apply(this, args);
          resolve(result);
        }, delay);
      }
    });
  };
  _debounce.cancel = function () {
    timer ? clearTimeout(timer) : '';
    timer = null;
    invoke = false;
  };
}
  • 使用回调函数参数callback
function debounce(func, delay, immediate = false, callback) {
  //存储上一次触发的timer
  let timer = null;
  //
  let invoke = false;
  return function _debounce(...args) {
    //清除上一次触发的timer
    timer ? clearTimeout(timer) : '';
    //在触发延迟回调前只执行一次
    if (immediate && !invoke) {
      invoke = true;
      const result = func.apply(this, args);
      //利用回调函数把返回值抛出
      if (callback) callback(result);
    } else {
      timer = setTimeout(() => {
        //触发回调后 再次初始化
        invoke = false;
        //绑定调用该函数上下文的this
        const result = func.apply(this, args);
        if (callback) callback(result);
      }, delay);
    }
  };
  _debounce.cancel = function () {
    timer ? clearTimeout(timer) : '';
    timer = null;
    invoke = false;
  };
}

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...