手撕代码——节流与防抖

欢迎大家来到手撕代码系列,本期介绍的是前端常见的节流与防抖的内容,包括节流与防抖的定义、它们的示例代码、它们常见的业务场景。如有错误,烦请各位大佬指正,主打一个听劝!

在开发中我们经常会遇到一些高频率事件,比如:鼠标移动,滑动窗口,键盘输入,按钮点击等等。无论是节流还是防抖,其实都是对于这种高频率事件的一种优化,如果我们的事件不需要那么高的触发频率,节流防抖是一种很好的性能优化方案。

节流

定义

节流是指在某个事件持续触发时,限制一定时间间隔只执行一次回调函数。

举个很生动的例子,就像游戏里面的普通攻击一样,无论你在一次普攻动作时间内点多少次普攻键,它都只会普攻一下。

业务场景

假设我们假设有一个按钮,点击一次就能造成页面上出现某些过渡效果,我们假设这个过渡动画为1s,此时我们不希望用户点击过快导致1s的动画还没结束就进入下一个动画,因此我们可以对这个过渡动画的回调函数进行节流处理。

示例代码

时间戳实现

以下这段节流代码是3s内只能触发一次回调函数,通过计算两个时间戳的差值来实现,当触发回调函数后又重新重置pretime,重新开始3s的节流处理。同时处理了send函数的this指向以及额外参数的问题。

注意:throttle函数会在第一次触发时就调用回调函数

html 复制代码
<body>
  <button id="btn">提交</button>
</body>

<script>
  function send(msg1,msg2) {
    console.log(msg1,msg2);
    console.log(this);
  }
  const btn = document.getElementById("btn");
  btn.addEventListener("click", throttle(send, 3000,'haha','hihi'));

  function throttle(fun, delay,...args) {
    let pretime = Date.now();
    return function () {
      if (Date.now() - pretime > delay) {
        //箭头函数,此时this就是指向btn
        fun.call(this, ...args); 
        // 如果调用成功重置pretime
        pretime = Date.now();
      }
    };
  }
</script>

定时器实现

这段代码通过定时器实现节流

注意:throttle2函数会时间到达后最后自动执行一次回调函数

html 复制代码
<body>
  <button id="btn">提交</button>
</body>

<script>
  function send(msg1,msg2) {
    console.log(msg1,msg2);
    console.log(this);
  }
  const btn = document.getElementById("btn");
  btn.addEventListener("click", throttle(send, 3000,'haha','hihi'));

  function throttle(fun, delay,...args) {
    let pretime = Date.now();
    return function () {
      if (Date.now() - pretime > delay) {
        //箭头函数,此时this就是指向btn
        fun.call(this, ...args); 
        // 如果调用成功重置pretime
        pretime = Date.now();
      }
    };
  }
</script>

防抖

定义

防抖指的是无论触发多少次事件,在事件触发最后一次后 n 秒后才执行。

就像游戏里面的回城一样,回城传送这个动作需要点击回城键几秒后才能实现,这几秒内如果我打断了回城这个动作那我就要重新开始计时。

业务场景

防抖最典型的业务场景就是搜索框了。当用户在搜索框内打字时,可能关键字还没有输入完毕,此时我们发送请求是无意义的,同时也会加重服务器的负担。于是我们通过防抖函数,设置为输入结束后0.5s才会发送请求 ,此时用户大概率输入完毕。

示例代码

定时器实现

防抖函数与上面节流函数定时器实现的不同在于每次被事件触发以后都会重置定时器进行计时。

js 复制代码
<body>
    <!-- 创建一个提交按钮 -->
    <button id="btn">提交</button> 
</body>
</html>
<script>
    function send(msg1,msg2){
        console.log(msg1,msg2,this);
        console.log('发送请求');
    }

    const btn = document.getElementById("btn");
    btn.addEventListener("click",debounce(send,1000,'hahah','ooo')) //给btn按钮绑定点击监听事件

    function debounce(fun,time,...args){
        let name
        return function(){
            if(name) clearInterval(name)
            name = setTimeout(() => {
                fun.call(this,...args)
            }, time);
        }
    }

</script>
相关推荐
迷迭绿3 小时前
Cesium 轨迹回放播放器
前端·javascript·cesium
HolySaga3 小时前
我用 UTS 写了一个三端同构的蓝牙插件(Android / iOS / 鸿蒙 NEXT),把踩过的坑都讲给你听
前端
程序员老赵4 小时前
Docker 部署 XWiki:轻松搭建企业知识库与协作 Wiki
前端·docker·开源
console.log('npc')4 小时前
第 10 章 更多业务模块扩展
前端·人工智能·大模型
行者全栈架构师4 小时前
我用 TRAE Work 把桌游之夜搬进了浏览器:一个计分器的从创意到上线
前端·算法·架构
山雀~4 小时前
线上CI流水打包失败排查思路案例
前端·ci/cd
时间的情敌4 小时前
《回顾 2019 前端:React Hooks 问世,前端工程化爆发的一年》
前端·react.js·前端框架
燕落南枝4 小时前
CSS 类选择器详解:从入门到实战
前端·css
tryCbest4 小时前
Vue3——第 7 篇:组件基础——从注册到使用的完整流程
前端·javascript·vue.js
ai工具集合5 小时前
图标集用法,前端项目 SVG 图标 icon 完整接入实操
前端