防抖(debounce)和节流(throttle)---解决事件频繁触发造成页面卡死

连续触发(触发频率很高)的时间,不进行优化,会出现页面卡顿现象。 常见的需要优化的事件:

  • 鼠标事件:

    • mousemove(拖拽)
    • mouseover(划过)
    • mouseWheel(滚屏)
  • 键盘事件:

    • keydown(按下键盘)
    • keypress(按下字符键盘)
    • keyup(弹起键盘)
  • window resize/scroll

优化方式是控制事件处理器在一段时间内的执行次

防抖

频繁(连续)触发事件(比如用户触发输入事件input),不执行目标动作,当不在触发事件了,再执行。

实现思路,在事件处理器内,使用 setTimeout 包裹目标动作,一直触发事件,就清除上次的定时器,不再触发触发事件,会执行最后一个定时器,目标动作也执行一次了。

<input type="text" id="input" />

JS代码:

function debounce(callback, delay) {
  let timeout = 0;
  return e => {
    console.log('清除', timeout, new Date());
    clearTimeout(timeout); //input 一直触发,就清除上一次的定时器,防止执行目标函数,直到事件不触发事件,最后一个定时器没有清除,delay 时间后就会执定时器,就确保了目标函数只执行一次。
    timeout = setTimeout(() => {
      callback(e);
    }, delay);
    console.log('新的', timeout, e.target.value, new Date());
  };
}
let print = debounce(e => {
  let value = e.target.value;
  console.log(value, new Date());
}, 1000);
document
  .querySelector('#input')
  .addEventListener('input', print, false);

清除定时器的时机很关键,在新定时器生成之前,如果在之后,会将所有定时器都清除,目标函数一次都不执行。

节流

防抖是多次触发事件,目标函数只执行一次,不管触发这些事件用了多少时间。而节流是在一段时间内,确保目标函数只执行一次,实现缓慢执行目标函数的效果。

上面的输入使用节流实现:

let thorttle = (callback, delay) => {
  let timeout = 0;
  let now = new Date() - 0;
  return e => {
    console.log('now', now);
    let last = new Date() - 0;
    clearTimeout(timeout);
    if (last - now >= delay) {
      console.log('时间间隔', last - now);
      callback(e);
      now = last;//将上执行的时间赋值给 now
    } else {
      //将 delay 时间内多次触发事件,目标函数合并到这里执行
      timeout = setTimeout(() => {
        callback(e);
      }, delay);
    }
  };
};
let write = thorttle(e => {
  console.log(e.target.value, new Date());
}, 5000);
document
  .querySelector('#input')
  .addEventListener('input', write, false);

两者比较

节流在某个时间段内,目标函数能执行一次,限制目标函数的执行频率,不管事件触发了多少次; 防抖是多次触发事件,目标函数只执行一次,不管触发了这些事件用了多少时间。

节流函数限制目标函数的执行频率,有连续变化的效果,适用于关注变化过程的操作,可以调整目标函数执行频率使得变化更加平滑,比如动画、改变窗口时执行某些操作等,常用事件resizescrollmouseWheeltouchmovemouseover等;

防抖函数适用于更关注结果的操作,不太关注操作过程,常见的事件有 inputkeyup等。

最后看一个 将 防抖 和 节流都用 resize 事件的效果,更能体会两者的区别:

function debounce(callback, delay) {
  let timeout = 0;
  return e => {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      callback(e);
    }, delay);
  };
}
let print = debounce(e => {
  let value = e.target.value;
  console.log('debounce', window.innerWidth);
}, 500);
let thorttle = (callback, delay) => {
  let timeout = 0;
  let now = new Date() - 0;
  return e => {
    let last = new Date() - 0;
    clearTimeout(timeout);
    if (last - now >= delay) {
      callback(e);
      now = last;
    } else {
      timeout = setTimeout(() => {
        callback(e);
      }, delay);
    }
  };
};
let write = thorttle(e => {
  console.log('thorttle', window.innerWidth);
}, 500);
window.addEventListener('resize', write, false);
window.addEventListener('resize', print, false);

参考

函数节流与函数防抖 函数防抖与函数节流

原文链接:segmentfault.com

上一篇:stringify
下一篇:generate-js

相关推荐

  • 项目启动提示安装 throttle-debounce/debounce throttle-debounce/throttle

    项目启动提示:npm install --save throttle-debounce/debounce throttle-debounce/throttle,但是又无法安装问题: 在最近正常运行的项...

    8 个月前
  • 防抖(debounce)和节流(throttle)的学习总结

    防抖(debounce) 用户与网页进行交互时,经常出现根据页面的状态、数据向服务器请求、发送数据的场景,比如:根据用户的输入数据进行实时校验,下拉请求数据等等,如果用户操作过于频繁,页面状态、数据变...

    2 年前
  • 说说JavaScript中函数的防抖 (Debounce) 与节流 (Throttle)

    为何要防抖和节流 有时候会在项目开发中频繁地触发一些事件,如 resize、 scroll、 keyup、 keydown等,或者诸如输入框的实时搜索功能,我们知道如果事件处理函数无限制调用,会大大加...

    1 年前
  • 浅谈Debounce 与 Throttle

    debounce 与 throttle 是开发中常用的高阶函数,作用都是为了防止函数被高频调用,换句话说就是,用来控制某个函数在一定时间内执行多少次。 使用场景:比如绑定响应鼠标移动、窗口大小调整、滚...

    3 年前
  • 浅析防抖debounce和节流throttle的区别

    前言:我们日常的需求开发过程中,对节流和防抖这两个概念 应该都不陌生, 在处理高频的触发事件,比如:监听scroll、resize等事件以及提交按钮的处理上都会使用到。

    4 个月前
  • 模拟实现underscore中的防抖(debounce)

    防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。使用: &lt;!DOCTYPE htm...

    6 个月前
  • 模拟实现underscore中的节流(throttle)

    函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。使用 &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;he...

    6 个月前
  • 快速 TypeScript 化 lodash 中的 throttle & debounce 函数

    1、背景 1.1、需要 TS 包 TypeScript 写起来爽,然而如果遇到没有现成的 TS 化的工具函数,就需要自己想办法弄出一份类型声明文件了。 前两天要写的小工具库(Typescript 语言...

    1 年前
  • 如何实现函数防抖 underscore lodash 关于debounce解析

    目录 概念 实现 参考 debounce 之 underscore 篇 debounce 之 lodash 篇 完善 问答 总结 概念 关于防抖是没有标准定义的,所以只能意会... 在某时间...

    4 个月前
  • 吐槽一下函数防抖 debounce 与函数节流 throttle,说说更好的函数节流 betterThrottle

    技术圈内总有人喜欢故弄玄虚,把简单的事情说复杂。首先表明一下个人看法:现在网上常见的“函数节流”和“函数防抖”,本质上都是“函数节流”,是“函数节流”的不同实现,它们目的都是降低被连续调用的函数的实际...

    9 个月前

官方社区

扫码加入 JavaScript 社区