节流与防抖

2023-11-20

1.我们先了解为什么要节流和防抖

我们给一个inpu输入框绑定一个oninput事件,此时我们输入“前端开发”四个字,我们

观察以下后台打印

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" />
    <script>
        const inp = document.querySelector('input');
        inp.oninput = function() { //我们给input输入框绑定了一个input事件
            console.log(this.value);
        }
    </script>
</body>

</html>

 我们仅仅输入四个字,就触发了几十次事件,

如果说我每一次输入都和后台进行数据交互,那么将会很影响计算机的性能。

因此我们需要让请求的次数大大减少,因此我们需要利用防抖来减少用户操作过多,与后台数据交互的次数。

接下来我们来介绍防抖

2.防抖

防抖:用户触发事件过于频繁,只要最后一次事件的操作。

也就是说,用户频繁的操作,我们只取最后一次操作。

比如

同样我们输入‘前端开发’四个字,如果我们输入的时间间隔小于0.5秒,就不触发oninput事件,

如果我们输入的时间间隔大于0.5秒,那么我们就触发oninput。

这样我们就大大减少了请求的次数。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" />
    <script>
        const inp = document.querySelector('input');
        let t = null;
        inp.oninput = function() { //我们给input输入框绑定了一个input事件
            if (t !== null) {
                clearTimeout(t)
            }
            t = setTimeout(() => {
                console.log(this.value)
            }, 500)
        }
    </script>
</body>

</html>

 如图,我们只要输入的时间间隔小于0.5秒,就不会触发oninput事件,只有当我们的输入的时间间隔超过0.5秒时,才会触发该事件。对比之下,我们触发的次数少了很多。

虽然以上代码完成了防抖的效果,但是还可以再优化一下,为什么要优化呢

在我们写的代码中只有console.log(this.value) 是真正的业务逻辑代码

 而且我们还定义了一个全局变量t,

以及这部分是防抖代码和业务代码混在一起,

           //防抖的逻辑和业务逻辑混在一起了
             if (t !== null) {
                clearTimeout(t)
            }
            t = setTimeout(() => {
                console.log(this.value) //真正的业务逻辑代码
            }, 500)

,而且该部分代码可读性不太好,别人需要看半天才知道是防抖,因此我们需要优化一下。 

我们可以通过闭包来优化防抖代码

使用闭包可以不用产生全局变量t,并且可以让防抖代码与业务代码隔离;

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" />
    <script>
        const inp = document.querySelector('input');
       

        inp.oninput = debounce(function() {
            console.log(this.value)
        }, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    fn();
                }, delay)
            }
        }
    </script>
</body>

</html>

很多人看到这里可能一头雾水,突然有点看不懂了,别着急,我来慢慢解释。

这里我们定义了一个防抖函数debounce

  inp.oninput = debounce();


   function debounce() {//防抖函数
            return function() {
               
            }
        }

我们知道inp.oninput事件=一个函数,

所以debounce返回一个函数,并且我们需要将相关逻辑作为参数,传给debounce

inp.oninput = debounce(function(){},500);//参数function(){}中执行业务代码,500是传入的延时时间


   function debounce(fn,delay) {//fn是要执行的业务逻辑,是函数//delay为定时器的延时事件
            let t=null;
            return function() {
               if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    fn(); //执行的业务代码
                }, delay)
            }
        }

接着

 inp.oninput = debounce(function() {
            console.log(this.value)
        }, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    fn();
                }, delay)
            }
        }

我们运行一下代码,输入

发现输出的是undefind 


 我们打印一下this,发现打印的是window,

 inp.oninput = debounce(function() {
            console.log(this)//打印this
        }, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    fn();
                }, delay)
            }
        }

 

因此我们需要在改变this的指向,也就是改变参数fn的this的指向

 inp.oninput = debounce(function() {
            console.log(this)//打印this,指向window
        }, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    console.log(this)//指向input
                    fn();//fn的this指向window
                }, delay)
            }
        }

改变this指向后的代码

 inp.oninput = debounce(function() {
            console.log(this.value)        
}, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                   
                    fn.call(this);//通过call改变this指向
                }, delay)
            }
        }

 这样防抖代码优化完了。

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" />
    <script>
        const inp = document.querySelector('input');


        inp.oninput = debounce(function() {
            // console.log(this);
            console.log(this.value)
        }, 500);

        function debounce(fn, delay) {
            let t = null;
            return function() {
                if (t !== null) {
                    clearTimeout(t)
                }
                t = setTimeout(() => {
                    fn.call(this);
                }, delay)
            }
        }
    </script>
</body>

</html>

3.节流

什么是节流?

节流:控制高频事件的执行次数(事件频繁触发时,每隔多少秒触发一次)

防抖是只执行最后一次,而节流是减少执行次数。

我们先做一个滚动事件,只要我们让滚动条滚动就会打印123,如下图,我们只是滚动了一下,

就触发了一百多次,如果是和后台服务器产生数据交互,同样对性能消耗是比较大的。

因此我们需要节流。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 2000px;
        }
    </style>
</head>

<body>
    <script>
        window.onscroll = function() {
            console.log(123);
        }
    </script>
</body>

</html>

此时需要节流,来减少执行的次数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 2000px;
        }
    </style>
</head>

<body>
    <script>
        let flag = true;
        window.onscroll = function() {
            if (flag) {
                setTimeout(() => {
                    console.log('123');
                    flag = true;
                }, 500)
            }
            flag = false;
        }
    </script>
</body>

</html>

代码优化后

  window.onscroll = throttle(function() {
            console.log(123);
        }, 500)

        function throttle(fn, delay) {
            let flag = true;
            return function() {
                if (flag) {
                    setTimeout(() => {
                        fn.call(this);
                        flag = true;
                    }, delay)
                }
                flag = false;
            }
        }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

节流与防抖 的相关文章

随机推荐

  • "我为区块链赋能实体经济代言"第二批代言人:复旦大学张江研究院教授陈文君

    我为区块链赋能实体经济代言 推出以来 颇受行业关注 为进一步规范行业发展 落实区块链赋能实体经济的目标 为行业发展 正本清源而发声 新一轮的 我为区块链赋能实体经济代言 于9月3日重磅启动 我为区块链赋能实体经济代言100人第二批 第3位代
  • JPEG编码原理与解码分析

    JPEG编码原理 JPEG Joint Photographic Experts Group 是JPEG标准的产物 该标准由国际标准化组织 ISO 制订 是面向连续色调静止图像的一种压缩标准 JPEG格式是最常用的图像文件格式 后缀名为 j
  • 数据挖掘—数据预处理

    文章目录 数据预处理 1 数据清洗 缺失值处理 异常值处理 2 数据集成 实体识别 冗余属性识别 数据变换 简单函数变换 规范化 连续属性离散化 属性构造 3 数据规约 属性归约 数值归约 Python主要数据预处理函数 数据预处理 数据预
  • 【uniapp】使用canvas组件编译到微信小程序兼容出错问题

    使用uniapp编译跨平台项目会遇到不少兼容问题 这里主要讲canvas组件的 编译到微信小程序会有兼容出错问题 这里给讲一下解决方案 希望有帮助 常见问题 draw无法绘制图形 如果使用CanvasContext绘制 以下代码 编译到微信
  • 值得收藏的UmiJS 教程

    点击上方关注 前端技术江湖 一起学习 天天进步 前言 网上的umi教程是真的少 很多人都只写了一点点 很多水文 所以打算自己写一篇 自己搭建umi 并封装了一下常用的功能 并用到公司实际项目中 umi介绍 Umi 是什么 Umi 中文可发音
  • maven学习笔记 maven的使用

    新建maven项目 使用mvn archetype generate命令新建一个maven项目 maven会自动下载必要的插件 还会下载一个所有项目模板的分类文件 这个文件有好几兆的大小 因此可能会持续比较长的时间 下载完毕之后 就会列出所
  • JAVA 8 新特性及使用

    1 前言 2019年9月19日java13已正式发布 感叹java社区强大 经久不衰 由于国内偏保守 新东西总要放一放 让其他人踩踩坑 等稳定了才会去用 并且企业目的还是赚钱 更不会因为一个新特性去重构代码 再开发一套程序出来 甚者国内大多
  • 不一样的联宇益通,不一样的SD-WAN+

    点击上方 中国云报 可关注 笔者有点挠头 究竟该用哪个词来描述联宇益通 Netpas 公司呢 低调 技术控 特立独行 还是自得其乐 似乎都有些影子 但又都不是最准确的表达 与联宇益通创始人兼CEO谢毅斌聊得越深入 感觉联宇益通身上矛盾的地方
  • 软件测试 app自动化02 Appium常用的元素定位工具 元素的属性 元素定位方法

    文章目录 1 Appium常用的元素定位工具 1 1 uiautomatorviewer 1 2 Appium Inspector 1 3 Weditor 2 元素的属性 3 元素定位方法 小结 1 Appium常用的元素定位工具 1 1
  • 数据库学习笔记(8)——mysql中的函数和存储过程

    1 MySQL中的函数 1 数据库主要做存储和查询操作 逻辑操作一般不在数据库中进行操作 2 MySQL中的函数主要是自定义函数 其中自定义函数格式如下 修改语句结束符 delimiter create function 函数名 参数名 数
  • 操作系统常见面试题

    1 什么是进程 Process 和线程 Thread 有何区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动 进程是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体 是CPU调度和分派的基本单位 它是比进程更小的能
  • java-线程锁

    实现锁 1 同步代码块 2 同步方法 在方法的头部加上synchronized 3 Lock 功能比synchronized更加的强大 但是加锁的时一定不要忘记解锁unlock 在使用lock锁时 想要实现睡眠唤醒功能 就要使用condit
  • 决策报表---动态参数实现多级下拉折叠菜单

    1 描述 在报表开发中 我们会遇到报表需要对行标题实现展开收起的折叠菜单的效果 这种效果一般在分析预览或者填报中应用下拉树控件来实现 但是在分页预览或者决策报表如何实现呢 这里我们使用动态参数的方式 预期效果 1 在分页预览和决策报表中能适
  • 操作系统中的线程&进程和同步&异步和并发&并行

    操作系统中的线程 进程和同步 异步和并发 并行 一 进程和线程 1 1 进程 1 2 线程 1 3 实现多任务的方法 1 3 1 使用多进程实现多任务 1 3 2 使用多线程 单个进程包含多个线程 实现多任务 1 3 3 使用多进程 多进程
  • vue+element中如何设置单个el-date-picker开始时间和结束时间关联

    功能 选了开始时间 则结束时间只能选择开始时间之后的 选了结束时间 则开始时间只能选择结束时间之前的 重点是picker options属性 图示 代码展示 body 内部
  • JavaScript设计模式-02-单例模式

    Javascript 设计模式 02 单例模式 简介 单例就是保证一个类只有一个实例 实现的方法一般是先判断实例是否存在 如果存在直接返回 如果不存在就创建了再返回 确保了一个类只有一个实例对象 在JavaScript里 单例作为一个命名空
  • AIGC(AI Generated Content,人工智能生成内容)

    AIGC AI Generated Content 人工智能生成内容 什么是AIGC AIGC Artificial Intelligence Generated Content AI Generated Content 中文译为人工智能生
  • 读《effective modern c++》笔记总结

    文章目录 一 类型推导与auto 模板类型推导 ParamType是一个指针或引用 但不是通用引用 ParamType是一个通用引用 ParamType即不是指针也不是引用 数组实参 函数实参 auto类型推导 二 decltype的理解
  • make menuconfig报错:Build dependency: Please install Git (git-core) >= 1.6.5

    版本号为chaos calmer 15 05 1 注意 在执行make menuconfig的时候 会报一个错误 如下 Build dependency Please install Git git core gt 1 6 5 这是open
  • 节流与防抖

    1 我们先了解为什么要节流和防抖 我们给一个inpu输入框绑定一个oninput事件 此时我们输入 前端开发 四个字 我们 观察以下后台打印