【性能优化】函数的防抖与节流

299 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

函数防抖

用手风琴案例演示,做防抖优化前和优化后的区别

简易手风琴案例(防抖优化前 )

图片资源地址: (github.com/jiang-zi/Op…)

    <style>
      ul {
        list-style: none;
      }

      * {
        margin: 0;
        padding: 0;
      }

      div {
        width: 1200px;
        height: 400px;
        margin: 50px auto;
        border: 1px solid red;
        overflow: hidden;
      }

      div li {
        width: 240px;
        height: 400px;
        float: left;
        transition: all 500ms;
      }

      div ul {
        width: 1200px;
      }
    </style>
  </head>

  <body>
    <div id="box">
      <ul>
        <li>
          <a href="#">
            <img src="./images/1.jpg" alt="" />
          </a>
        </li>
        <li>
          <a href="#">
            <img src="./images/2.jpg" alt="" />
          </a>
        </li>
        <li>
          <a href="#">
            <img src="./images/3.jpg" alt="" />
          </a>
        </li>
        <li>
          <a href="#">
            <img src="./images/4.jpg" alt="" />
          </a>
        </li>
        <li>
          <a href="#">
            <img src="./images/5.jpg" alt="" />
          </a>
        </li>
      </ul>
    </div>
  </body>
  <script>
    //1.获取元素
    let liList = document.querySelectorAll('#box li')
    let box = document.querySelector('#box')

    //2.注册事件
    //2.1 鼠标移入
    for (let i = 0; i < liList.length; i++) {
      liList[i].onmouseenter = function () {
          //3.排他思想修改宽度: 我自己800px,其他人100px
          for (let j = 0; j < liList.length; j++) {
            if (i === j) {
              liList[j].style.width = '800px'
            } else {
              liList[j].style.width = '100px'
            }
          }
      }
    }

    //2.2 鼠标移出父盒子
    box.onmouseleave = function () {
      //3.设置每一个li元素宽度240
        for (let i = 0; i < liList.length; i++) {
          liList[i].style.width = '240px'
        }
    }
  </script>

结论 : 做函数防抖优化前,多次移入手风琴区域会出现抖动感。用户体验极其不好,还有内存资源得浪费。

解决方法 : 函数防抖

什么是函数防抖 : 间隔时间内 多次触发事件,以最后一次为准

函数防抖思路 :

  1. 声明一个变量存储定时器id
  2. 每一次触发事件的时候,先清除上一次的定时器,以本次为准
  3. 开启定时器,间隔时间之后再触发事件处理函数
    • 此时只要用户在这个间隔时间之内触发了其他事件,那么上一次的定时器就会被清除
    //防抖第一步:声明变量存储定时器id
    let timeID = null

    //2.注册事件
    //2.1 鼠标移入
    for (let i = 0; i < liList.length; i++) {
      liList[i].onmouseenter = function () {
        //防抖第二步: 每一次触发事件的时候,都要把上一次的定时器给移除。 以最后一次为准
        clearTimeout(timeID)
        //防抖第三步:每一次触发事件的时候,先不触发。开启定时器,间隔时间之后再触发
        timeID = setTimeout(function () {
          //3.排他思想修改宽度: 我自己800px,其他人100px
          for (let j = 0; j < liList.length; j++) {
            if (i === j) {
              liList[j].style.width = '800px'
            } else {
              liList[j].style.width = '100px'
            }
          }
        }, 300)
      }
    }

    //2.2 鼠标移出父盒子
    box.onmouseleave = function () {
      //3.设置每一个li元素宽度240
      clearTimeout(timeID)
      timeID = setTimeout(function () {
        for (let i = 0; i < liList.length; i++) {
          liList[i].style.width = '240px'
        }
      }, 300)
    }

函数节流

什么是函数节流 : 间隔时间内函数只被触发一次

函数节流作用: 降低高频事件的触发频率

  高频事件: 触发频率很高的事件  如 : onmousemove  onscroll

函数节流思路:

  1. 声明变量存储本次触发的时间time
  2. 每一次触发的时候, 使用 当前时间 - time,判断两次间隔是否超过 节流时间 超过: 触发,并且存储本次触发时间。 不超过:不触发

示例 :

      //节流第一步: 存储变量记录触发时间
      let time = null
        
      let i = 1
      //高频事件:鼠标移动
      window.onmousemove = function () {
        //节流第二步: 判断两次间隔是否超过 节流时间
        let currentTime = Date.now()
        if( currentTime - time >= 10000 ){
            i++
            console.log('鼠标移动触发次数:' + i )
            //节流第三步: 存储本次触发时间
            time = currentTime
        } 
      }
    //   let j = 1
      //高频事件:鼠标滚动
    //   window.onscroll = function(){
    //     j++
    //     console.log('鼠标滚动条触发次数:' + j )
    //   }

函数的防抖与节流总结

函数防抖及应用场景:

  1. 函数防抖 : 间隔时间 内多次触发事件以最后一次为准
  2. 应用场景 : 鼠标移入/移出 、 键盘输入框

函数节流及应用场景:

  1. 函数节流 : 间隔时间 内事件只会触发一次
  2. 应用场景 : 高频事件 鼠标移动 鼠标滚动条

防抖与节流异同点 :

相同点: 都是为了优化函数执行频率,提高网页性能

不同点:

  • 防抖: 优化‘用户主动‘触发的事件, 多次触发以最后一次为准
  • 节流: 优化‘事件本身’执行的频率, 间隔时间只执行一次

搜索框防抖案例

    <input type="text" placeholder="请输入搜索内容" />
    <script>
      let timeID = null

      document.querySelector('input').oninput = function () {

        //清除上一次定时器,以本次为准
        clearTimeout(timeID)
        //开启本次防抖定时器
        /* 
        细节:定时器中的this,默认指向window
        如果定时器函数是箭头函数,则会访问上一次this : 事件源
        */
        timeID = setTimeout(()=>{
            console.log(this.value)
        },300)

      }
    </script>