• 前端性能优化之防抖&节流


    前言

    大家好,我是南木元元,热衷分享有趣实用的文章。

    什么是防抖&节流

    防抖和节流是前端开发中常用的两种性能优化技术。

    为什么需要防抖和节流呢?

    两者目的都是为了防止某个时间段内操作频繁触发,造成性能消耗。

    防抖:在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。

    节流: n 秒内只执行一次事件,即使n 秒内事件重复触发,也只有一次生效。

    可能很多人看了概念还是不太清楚这两者到底有什么区别,下面就通过一个简单的案例来说明。

    let btn = document.getElementById('btn')
    //模拟发送请求
    function req(){
      console.log('发送请求')
    }
    btn.addEventListener('click', req)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    以上代码简单实现了一个点击按钮的事件,每点击一次按钮就调用一次函数发送请求,效果如下:

    在这里插入图片描述
    如果对函数做了防抖

    btn.addEventListener('click', debounce(req, 1000)) //防抖,时间设为1秒
    
    • 1

    1秒内疯狂点击按钮,事件都不会被触发,只有当不再点击按钮后,过了1秒,事件才被触发。效果是下面这样的:

    在这里插入图片描述

    如果对函数做了节流

    btn.addEventListener('click',throttle(req, 1000)) //节流,时间设为1秒
    
    • 1

    1秒内疯狂点击按钮,事件都只被触发一次。效果是下面这样的:

    在这里插入图片描述

    由此可以看出,两者的区别:防抖是一段时间内只执行最后一次,节流是一段时间内只执行一次。如下图所示:

    在这里插入图片描述

    代码实现

    下面就来分别实现一下防抖和节流。

    实现防抖

    防抖的实现思路:使用闭包来保存定时器变量 timer。事件触发后开启一个定时器,如果在 delay 时间内再次触发事件,就会清除之前的

    定时器并设置一个新的定时器,直到 delay 时间内不再触发事件,定时器到达时间后执行传入的函数 fn。

    function debounce(fn, delay = 500) {
        let timer = null;
        // 这里返回的函数是每次用户实际调用的防抖函数
        return function(...args) {	
        	// 如果已经设定过定时器了就清空上一次的定时器
        	if(timer) {
            	clearTimeout(timer);	
            }
            // 开始一个新的定时器,延迟执行用户传入的方法,这里必须是箭头函数,要让this指向fn的调用者
            timer = setTimeout(() => {  
            	fn.apply(this, args);   
            }, delay)	
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    实现节流

    节流的实现思路:同样使用闭包来保存定时器变量 timer。每次触发事件时,如果定时器不存在,就设置一个定时器,并在 delay 时间后

    执行传入的函数 fn。如果在 delay 时间内再次触发事件,由于定时器还存在,就不会执行传入的函数 func。

    function throttle(fn, delay = 500) {
        let timer = null;
        return function(...args) {
        	// 当前有任务了,直接返回
            if(timer) {
            	return;
            }
            timer = setTimeout(() => {
                fn.apply(this, args);
                //执行完后,需重置定时器,不然timer一直有值,无法开启下一个定时器
                timer = null;	
            }, delay)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    节流还有一种更简单的时间戳版本,思路就是两次触发的时间间隔到了指定时间就执行,否则不执行。

    function throttle(fn, delay = 500) {
      let prev = Date.now();// 上一次时间
      return function(...args) {
        let now = Date.now();//当前时间
        // 时间间隔到了就执行函数
        if (now - prev >= delay) {
          fn.apply(this, args);
          prev = Date.now();
        }
      };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    应用场景

    防抖的应用

    防抖的主要应用场景是优化搜索框的输入,用户在不断输入值时,用防抖来节约请求资源,当用户最后一次输入完,再发送请求。

    案例:搜索查询

    <body>
    <input type="text" id="search" />
    <script>
      const search = document.getElementById("search");
      //模拟发送请求
      function req() {
        console.log('发送请求查询结果...');
      }
      search.addEventListener('keyup', req);
    script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行效果如下:

    在这里插入图片描述
    如上所示,在表单中输入内容,键盘弹起时就会触发keyup事件,发送请求去查询内容,这样频繁的触发事件发送请求会增加性能消耗,

    同时也会增加服务器的压力,并且实际应用中,只需用户最后一次输入完,再发送请求,于是我们可以使用防抖进行优化。

    <body>
    <input type="text" id="search" />
    <script>
      const search = document.getElementById("search");
      //模拟发送请求
      function req() {
        console.log('发送请求查询结果...');
      }
      function debounce(fn, delay = 500) {
        let timer = null;
        return function(...args) {	
        	if(timer) {
            	clearTimeout(timer);	
            }
            timer = setTimeout(() => {  
            	fn.apply(this, args);   
            }, delay)	
        }
      }
      search.addEventListener('keyup', debounce(req, 1000));
    script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    防抖后的效果:

    在这里插入图片描述
    可以看到,利用防抖,当用户频繁输入时,并不会发送请求,只有在指定间隔内没有输入时,才触发查询,这样就提高了浏览器性能。

    节流的应用

    节流的主要应用场景是优化滚动事件,当用户滚动页面时,会频繁触发滚动事件,使用节流可以控制滚动事件的触发频率,避免过多的计算和渲染操作,提高页面的性能和流畅度。

    案例:监听计算滚动条位置

    //模拟计算滚动位置
    function compute() {
      console.log('计算滚动条位置');
    }
    window.addEventListener('scroll', compute)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行效果如下:
    在这里插入图片描述
    如上所示,有些场景下需要去计算判断滚动条的位置,比如是否加载更多,当我们滚动浏览器的滚动条时,会频繁触发scroll事件,造成频繁的判断滚动条位置,可以利用节流进行优化。

    //模拟计算滚动位置
    function compute() {
      console.log('计算滚动条位置');
    }
    function throttle(fn, delay = 500) {
      let prev = Date.now();
      return function(...args) {
        let now = Date.now();
        if (now - prev >= delay) {
          fn.apply(this, args);
          prev = Date.now();
        }
      };
    }
    window.addEventListener('scroll', throttle(compute, 200))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    节流后的效果:

    在这里插入图片描述
    可以看到,利用节流,可以按一定时间的频率来计算判断滚动条位置,然后决定是否加载更多,这样就能减少浏览器性能的消耗。

    结语

    🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~

  • 相关阅读:
    UVA 401 回文词 Palindromes
    2023高教社杯全国大学生数学建模竞赛B题代码解析
    【正点原子I.MX6U-MINI应用篇】3、Framebuffer应用编程,操作屏幕
    【Visual Leak Detector】QT 中 VLD 输出解析(二)
    规则解读(一)| 本地资源检测 For Unreal
    java-后端调用第三方接口返回图片流给前端
    Linux驱动开发 驱动程序的具体编写及出口入口函数解析,printk打印内核信息
    VSCODE中配置JavaScript编译环境
    开发神技!阿里消息中间件进阶手册限时开源,请接住我的下巴
    2018架构真题&案例(四十九)
  • 原文地址:https://blog.csdn.net/weixin_43288600/article/details/133623301