深入浅出 - 防抖 & 节流

180 阅读4分钟

性能优化篇 防抖和节流

防抖(debounce)

image.png

what

事件触发的规定时间内只运行最后一次

when
  • 搜索框实时搜索
  • 获取鼠标最后移动位置
  • 窗口尺寸变换
how

定时器思路:用户触发后,判断是否含有旧定时器,含有则清空, 定义一个新的定时器,时间自定,内部是应用代码。

/**
 * 声明 定时器
 * @type {number | undefined}
*/
let Timer;

/**
 * 防抖函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
*/
function Debounce(fun, t = 500) {
  // 含有旧定时器?清空
  Timer && clearTimeout(Timer);
  // 定义定时器,执行应用代码
  Timer = setTimeout(() => {
    fun();
  }, t);
}
封装
全局变量模式
/**
 * 声明 定时器
 * @type {number | undefined}
*/
let Timer;

/**
 * 防抖函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
*/
function Debounce(fun, t = 500, ...rest) {
  // 含有旧定时器?清空
  Timer && clearTimeout(Timer);
  // 定义定时器,执行应用代码
  Timer = setTimeout(() => {
    fun.apply(this, rest);
  }, t);
}

example

Debounce((a, b)=>{console.log(a, b);}, 3000, 'hello', 'world')
闭包模式
/**
 * 防抖函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @returns {function}
*/
function Debounce(fun, t = 500) {
  let Timer;
  return function (...rest) {
    // 含有旧定时器?清空
    Timer && clearTimeout(Timer);
    // 定义定时器,执行应用代码
    Timer = setTimeout(() => {
      fun.apply(this, rest);
    }, t);
  }
}

example

function fun(a, b) {
  console.log(a + b);
}
const newPrint = Debounce(fun, 3000);
newPrint('hello', 'world');
带返回值的封装封装
全局变量模式
/**
 * 声明 定时器
 * @type {number | undefined}
*/
let Timer;

/**
 * 防抖函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
*/
function Debounce(fun, t = 500, ...rest) {
  // 含有旧定时器?清空
  Timer && clearTimeout(Timer);
  return new Promise(resolve => {
    // 定义定时器,执行应用代码
    Timer = setTimeout(() => {
      resolve(fun.apply(this, rest));
    }, t);
  })
}

Example

function add(a, b) {
  return a + b;
}
Debounce(add, 3000)('1', '2').then(res => {
  console.log('res:', res);
})
闭包模式
/**
 * 防抖函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @returns {function} 抛出函数
*/
function Debounce(fun, t = 500) {
 let Timer;
 return function (...rest) {
   return new Promise((resolve) => {
     // 含有旧定时器?清空
     Timer && clearTimeout(Timer);
     // 定义定时器,执行应用代码
     Timer = setTimeout(() => {
       resolve(fun.apply(this, rest));
     }, t);
   });
 }
}

Example

function fun(a, b) {
  return a + b;
}
const print = Debounce(fun, 3000);

// promise then回调函数
print('1', '2').then(res => {
  console.log('res:', res);
})

// await
let res = await print('1', '2');
console.log(res);

节流(Throttle)

image.png

what

规定时间内,只触发一次应用程序

when
  • 点击按钮
  • 页面滚动
  • 动画场景
how

如果在时间范围外,运行应用程序,设置一个时间范围

/**
 * 声明 运行变量
 * @type {boolean}
*/
let active;

/**
 * 节流函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
*/
function Throttle(fun, t = 500) {
  // 没有运行
  if (!active) {
    // 运行应用程序
    fun();
    // 设置时间范围
    active = true;
    setTimeout(()=> {
      active = false;
    }, t);
  }
}
封装
全局变量模式
/**
 * 声明 运行变量
 * @type {boolean}
*/
let active;

/**
 * 节流函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @param  {...any} rest 回调函数所需参数
*/
function Throttle(fun, t = 500, ...rest) {
  // 在时间范围外
  if (!active) {
    // 运行应用程序
    fun.apply(this, rest);
    // 设置时间范围
    active = true;
    setTimeout(()=> {
      active = false;
    }, t);
  }
}

example

Throttle((a, b)=>{console.log(a, b);}, 3000, 'hello', 'world');
闭包模式
/**
 * 节流函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @returns {function} 返回函数
*/
function Throttle(fun, t = 500) {
  let active;
  return function(...rest) {
    // 在时间范围外
    if (!active) {
      // 运行应用程序
      fun.apply(this, rest);
      // 设置时间范围
      active = true;
      setTimeout(()=> {
        active = false;
      }, t);
    }
  }
}

example

function fun(a, b) {
  console.log(a + b);
}
const newPrint = Throttle(fun, 3000);
newPrint('hello', 'world');
带返回值的封装封装
全局变量模式
/**
 * 声明 运行变量
 * @type {boolean}
*/
let active;

/**
 * 节流函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @param  {...any} rest 回调函数所需参数
*/
function Throttle(fun, t = 500, ...rest) {
  return new Promise((resolve, reject) => {
    // 在时间范围外
    if (!active) {
      // 运行应用程序
      resolve(fun.apply(this, rest));
      // 设置时间范围
      active = true;
      setTimeout(()=> {
        active = false;
      }, t);
    }
    else {
      reject('within protection time!');
    }
  })
}

Example

function add(a, b) {
  return a + b;
}
Debounce(add, 3000)('1', '2').then(res => {
  console.log('res:', res);
})
闭包模式
/**
 * 节流函数
 * @param {function} fun 要执行的回调函数
 * @param {number} t 时间差
 * @returns {function} 返回函数
*/
function Throttle(fun, t = 500) {
  let active;
  return function(...rest) {
    return new Promise((resolve, reject) => {
      // 在时间范围外
      if (!active) {
        // 运行应用程序
        resolve(fun.apply(this, rest));
        // 设置时间范围
        active = true;
        setTimeout(()=> {
          active = false;
        }, t);
      }
      else {
        reject('within protection time!');
      }
    })
  }
}

example

function fun(a, b) {
  return a + b;
}
const print = Debounce(fun, 3000);

// promise then回调函数
print('1', '2').then(res => {
  console.log('res:', res);
})

// await
let res = await print('1', '2');
console.log(res);

Thanks!