前端性能优化之防抖与节流,大幅度降低你的事件处理性能

简介: 看到这个标题就懵了, 你会有以下几个问题:什么是防抖? 什么是节流? 如何使用防抖? 如何使用节流? 什么时候需要用到防抖和节流? 为什么要用防抖和节流? 那我们就围绕这几个问题来讲一讲防抖与节流的两个概念和简单应用吧~ 我会在正文中给大家逐个解答问题

01

初步了解


如果你不想看具体过程,也可以直接跳到总结,不过还是希望你慢慢看下去哦,因为这对你理解这两个操作很有帮助。


首先,在正文开始之前我们来看一个例子,来了解一下应用防抖和节流的初衷。


先放代码, 其中css代码中,实现导航栏悬停的属性,不明白的可以去看我的上一篇文章介绍,只需要一分钟不到就可以明白


    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title>    <style>        .nav-bar{            height: 30px;            background: red;            /* 以下两个属性设置是为了实现导航栏的悬停 */            position: sticky;            top: 0;        }</style></head><body>    <div class="nav-bar">我是导航栏</div>    <div>我是内容1</div>    <div>我是内容2</div>    <div>我是内容3</div>    <div>我是内容4</div>    <div>我是内容5</div>    <div>我是内容6</div>    <div>我是内容7</div>    <div>我是内容8</div>    <div>我是内容9</div>        <!-- 此处省略很多div标签  -->
    <script>    window.onload = function () {      // 获取导航栏标签元素        let nav_bar = document.getElementsByClassName('nav-bar')[0]        //给window绑定滚动事件        window.onscroll = function () {          //每次触发滚动事件,打印导航栏离文档顶部的距离            console.log(nav_bar.offsetTop)        }    }</script></body></html>


    效果展示


    ef2b062c1ec54b0b295fb8f4ed91350f.jpg


    我们可以看到, scroll事件是一个频发事件,我们只是简单的往下滚动, 但scroll 事件却触发了很多很多很多次。但是我们的目的可能只是想获得滚动停下来以后导航栏距离文档顶部的距离, 我们并不需要滚动停止前那过程中变化的距离, 如果一直在滚动时去获取距离,这非常影响性能,这是我们就需要用到 防抖和节流了。


    02

    防抖


    (1)防抖的定义


    抖,听起来就是一个频繁触发的动作,我们可以想象我们在跑步,每跑一步就出很多的汗,我们跑的过程中,很想拿毛巾擦一擦汗,但是一想,如果刚擦完汗,跑几步就又出汗了,还不如不擦,我看看我等会还跑不跑,如果还跑,那我就一直不擦汗,如果我什么时候不跑了,我就开始擦一下汗。那么‘ 跑步 ’ 这个动作就可以看作我们上述代码中的滚动事件, ’擦汗 ’ 就可以看成scroll 事件的处理代码,即获取导航栏离文档顶部的距离。那么防抖,就是我们滚动页面,刚要获取导航栏离文档顶部的距离,但是发现等会还要继续滚动,那么就先不获取了,等什么时候停止滚动了,再获取这个距离。


    以上文字就是对防抖这个概念的一个形象的解释,希望大家反复阅读,理解了定义以后才方便理解下面的实现防抖的代码。


    (2)防抖的使用


    为了解决我们正文刚开始那个例子中,频繁获取导航栏离文档顶部的距离的现象,我们可以用一个setTimeout定时器来完成防抖功能


      // 这里我们只修改js代码,其他都不变
      <script>    window.onload = function () {        let nav_bar = document.getElementsByClassName('nav-bar')[0]        //初始化一个变量用于存储定时器        let timer = null        window.onscroll = function () {            //判断定时器是否还在运行            if(timer) {              //清除上一次事件创建的定时器                clearTimeout(timer)            }            //创建一个延迟为500ms的定时器并赋值给timer            timer = setTimeout(function () {              //定时器延迟过后获取导航栏离文档顶部的距离                console.log(nav_bar.offsetTop)            }, 500)
              }    }</script>


      我们来解读一下这段代码:


      1. 我们在全局定义了一个用于存放定时器的变量timer, 当我们在网页第一次滚动页面时,触发scroll 事件, 首先判断 timer 是否有定时器, 因为第一次滚动触发事件,并没有定时器赋值给timer,所以执行下面的代码, 这时给 timer 赋值一个延迟为500ms的定时器,并将获取导航栏离文档顶部距离的代码放在定时器中。


      1. 因为滚动事件是频繁触发的,紧接着又触发了 scroll 事件。同样的先判断 timer 是否有定时器, 因为上一次触发该事件给 timer 赋值了一个定时器, 但此时定时器还没结束, 所以 timer 是有定时器的,所以执行 if 语句里的代码, 将 timer 里的定时器给清除掉, 这时,因为在上一次定时器还没结束时,我们就在下一次触发事件时将上一次的定时器给清除掉了,所以上一次触发事件没有来得及运行获取导航栏离文档顶部距离的代码。接着我们又给 timer 赋值了一个定时器。


      1. 就这样在后面会触发无数次的滚动事件, 代码的运行会一直按照步骤2里的逻辑进行,这样循环往复……


      1. 直到我们停止滚动以后, 不再触发滚动事件了,最后一次滚动事件中给 timer赋值的 setTimeout 定时器 生效了,并打印了数据。


      现在,我们来看一下,运用了防抖之后滚动页面会有什么效果


      d8fbcc5118981455530e82c22c16f2b9.jpg


      我们可以很清楚的看到,在我们滚动的过程中,一直没有打印数据,直到我们停止以后, 控制台打印了导航栏离文档顶部的距离。这就是防抖的效果,现在你有没有对防抖有一个很深的印象了呢?接下来我们来介绍一下第二种处理频繁触发事件的方法:节流。


      03

      节流


      (1)节流的定义


      为了介绍节流的定义,我们继续使用跑步这一例子。想象我们在跑步,我们很热很热,在跑步的过程中,每隔几秒钟,拿毛巾擦一擦身上的汗。这里我们同样把 ’ 跑步 ’ 看作是 滚动页面的操作, 把 ’ 擦汗 ’ 看作是获取导航栏离文档顶部的距离的操作。那么,节流就是, 我们滚动页面,获取了一下导航栏离文档顶部的距离, 此时我们一直在滚动页面, 只不过我们刚获取过距离了,就先不获取了, 等距离上一次获取几秒后,我们再获取一次吧。


      也请大家仔细体会节流的含义,方便理解下面的代码


      (2)节流的使用


      节流的方法,有两种,一种是利用时间戳,另一种是利用定时器


      • 利用时间戳来完成节流


      代码如下:


        // 同样的这里也是只需要修改js代码
        <script>    window.onload = function () {        let nav_bar = document.getElementsByClassName('nav-bar')[0]        //初始化一个变量,用来存储上一次获取数据的时间戳        let last = 0        window.onscroll = function () {          //用来获取此时触发滚动事件时的时间戳            let now = Date.now()            //判断距离上次获取数据间隔了是否有1秒            if(now - last >= 1000) {                console.log(nav_bar.offsetTop)                //重置一下上一次获取数据时间戳                last = Date.now()            }        }    }</script>


        我们来解读一下这段代码:


        1. 我们刚开始滚动页面,触发滚动事件,获取当前时间戳, 因为是第一次触发该事件,last = 0 ,所以 if 语句成立,获取一次导航栏离文档顶部的距离,并给 last 赋值一个现在的时间戳。


        1. 因滚动事件频繁触发, 再一次触发了滚动事件,获取一下现在的时间戳,判断一下,现在的时间戳减去上一次操作结束时的时间戳,发现时间相差小于1秒,所以不获取导航栏离文档顶部的距离,同时也不用给 last 重新赋值一个此时的时间戳


        1. 就这样一直频繁触发滚动事件,按照步骤2循环往复……


        1. 直到距离上次操作超过1秒, now - last 大于1秒后,才会再一次获取导航栏离文档顶部的距离,并又一次给 last 赋值一个操作结束时的时间戳。


        现在,我们来看一下,利用时间戳节流之后滚动页面会有什么效果


        e938e1883ea9288a7cca02df0ff30ab8.jpg


        可以很明显的看到,利用时间戳节流以后,获取数据操作没有像初始的那样频繁触发了,而是只要你在滚动,每隔一定时间进行一次触发,这个时间你是可以自己随意定义的。


        • 利用定时器节流


        代码如下:


          // 这里也只需要修改js 代码<script>    window.onload = function () {        let nav_bar = document.getElementsByClassName('nav-bar')[0]        //存放定时器        let timer = null        //存放上一个定时器的状态        let status = false        window.onscroll = function () {          // 判断上一个定时器是否执行完毕            if(status === false) {              // 给status 赋值true,代表定时器正在执行                status = true                timer = setTimeout(function () {                    console.log(nav_bar.offsetTop)                    clearTimeout(timer)                    //定时器执行完毕,status赋值为false,告知执行完毕                    status = false                }, 1000)
                      }
                  }
              }</script>


          我们来解读一下这段代码:


          1. 首先刚开始进行滚动, status为 false,表示没有定时器在执行,所以给创建一个定时器并赋值给 timer


          1. 此时再一次触发滚动事件时,if 判断 status为 true , 表示上一次的定时器还在执行呢,所以就不做任何操作


          1. 就这样一直触发滚动事件,按照步骤2往复循环……


          1. 直到刚开始的定时器执行完毕以后,给 status赋值一个 false, 这时再触发滚动事件时, if 判断 status 为 false, 表示上一次的定时器执行完成了,于是才创建了新一轮的定时器,并赋值给 timer


          1. 从步骤2~步骤4 往复循环……


          现在,我们来看一下,利用定时器节流之后滚动页面会有什么效果


          e930b565b0cdfdb2bb655b13b99a3ab5.jpg


          我们能很清楚的看到, 利用定时器节流的效果跟利用时间戳节流的效果差不多,如果非要说差别的话,就是利用时间戳节流,第一次滚动会立马获取一次数据,而利用定时器节流, 第一次获取数据会延迟一定时间。


          04

          总结


          简单做个总结吧,防抖和节流的区别:


          1. 防抖是从频繁触发执行变为最后一次才执行


          1. 节流是从频繁触发执行变为每隔一段时间执行一次


          相关文章
          |
          4月前
          |
          前端开发 UED 开发者
          颠覆你的前端知识:防抖与节流的区别及实战解析!
          【8月更文挑战第23天】在Web前端开发中,处理用户界面交互产生的事件可能会影响性能。为此,我们有两种优化方法:防抖(debounce)和节流(throttle)。防抖确保函数仅在事件停止触发一段时间后执行一次,适用于如搜索自动补全场景。而节流则确保函数按固定时间间隔执行,不管用户操作频率如何。本篇技术博客将深入解析两者差异并提供示例代码,帮助开发者更好地理解和应用这些技巧以提升应用性能和用户体验。
          83 0
          |
          18天前
          |
          存储 编解码 前端开发
          惊!前端新手也能秒懂的高级技巧,轻松提升网页颜值与性能!
          本文针对前端新手,介绍了三个简单易学的高级技巧,帮助提升网页的颜值和性能。包括使用CSS框架快速美化网页、优化图片资源加快加载速度,以及利用ARIA属性和媒体查询提高网页的可访问性和响应性。示例代码清晰,适合初学者上手实践。
          26 3
          |
          2月前
          |
          前端开发
          前端常用方法防抖(debounce)和节流(throttle)的示例演示及应用场景说明
          前端常用方法防抖(debounce)和节流(throttle)的示例演示及应用场景说明
          25 0
          |
          3月前
          |
          缓存 边缘计算 前端开发
          关于前端性能优化问题,认识网页加载过程和防抖节流
          该文章详细探讨了前端性能优化的方法,包括理解网页加载过程、实施防抖和节流技术来提升用户体验和性能。
          |
          4月前
          |
          缓存 前端开发 JavaScript
          超时空加速秘籍:揭秘JavaScript前端开发中的性能魔法,让您的Web应用瞬间穿越到未来!
          【8月更文挑战第27天】本文介绍了一系列实用的JavaScript性能优化方法并提供了示例代码,包括减少DOM操作、使用事件委托、避免阻塞主线程、异步加载资源、利用浏览器缓存、代码分割以及使用Service Worker等技术,帮助开发者有效提升Web应用性能和用户体验。
          54 2
          |
          4月前
          |
          缓存 编解码 前端开发
          优化Web应用性能的前端技巧:从加载时间到用户体验
          在现代Web开发中,提升前端性能不仅仅是为了缩短页面加载时间,更是为了提供更流畅的用户体验。本文将探讨几种有效的前端优化技术,包括懒加载、代码拆分、资源压缩以及浏览器缓存策略。通过具体实例和最佳实践,读者将能够掌握如何系统地提高Web应用的响应速度,减少资源消耗,并最终改善用户的整体体验。
          |
          4月前
          |
          前端开发 JavaScript API
          一场前端框架的“武林大会”,三大主流框架之间的性能比较!!!
          一场前端框架的“武林大会”,三大主流框架之间的性能比较!!!
          |
          4月前
          |
          前端开发 UED 开发者
          React组件优化全攻略:深度解析让你的前端应用飞速运行的秘诀——从PureComponent到React.memo的彻底性能比较
          【8月更文挑战第31天】在构建现代Web应用时,性能是提升用户体验的关键因素。React作为主流前端库,其组件优化尤为重要。本文深入探讨了React组件优化策略,包括使用`PureComponent`、`React.memo`及避免不必要的渲染等方法,帮助开发者显著提升应用性能。通过实践案例对比优化前后效果,不仅提高了页面渲染速度,还增强了用户体验。优化React组件是每个开发者必须关注的重点。
          73 0
          |
          5月前
          |
          开发框架 前端开发 JavaScript
          在微信框架模块中,基于Vue&Element前端的事件和内容的管理
          在微信框架模块中,基于Vue&Element前端的事件和内容的管理
          |
          4月前
          |
          前端开发 JavaScript 开发者
          掌握Web前端事件处理精髓:从事件冒泡到事件委托,轻松优化你的交互体验与代码性能!
          【8月更文挑战第23天】在Web前端开发中,事件处理是实现用户交互的关键机制。其中,事件冒泡与事件委托是优化页面性能、简化代码的重要手段。事件冒泡是指事件从触发它的元素开始,沿着DOM树向上逐层传播至根节点的过程。通过阻止事件冒泡,可以控制事件的影响范围。而事件委托则是利用事件冒泡特性,在父元素上设置监听器来响应子元素的事件,这种方法减少了监听器的设置数量,特别适用于动态添加的子元素,提高了代码的可维护性和性能。掌握这两种技术,能帮助开发者构建更高效、更简洁的应用程序。
          56 0

          热门文章

          最新文章