JS:debounce(防抖)、throttle(节流)

       浏览器中有一些事件会高频率触发,比如:resize(窗口重置)、scroll(页面滚动)、mousemove(鼠标移动)等,监听这些事件,并按浏览器的触发频率响应,极可能造成页面卡顿、抖动,甚至浏览器崩溃,对此有两种解决方案:防抖(debounce ) 和 节流(throttling )
       debounce(防抖)和 throttle(节流)是一种编程技巧,用于控制某个函数在一定时间内执行多少次。主要用于平滑事件响应、减轻浏览器压力。
       1、debounce(防抖)
        策略:当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。 在后期又扩展了前缘debounce,执行动作在前,然后设定周期,周期内有事件被触发,不执行动作,且周期重新设定。
        简单来说,对多次触发事件的函数,在规定时间内,只执行一次 (第一次或最后一次)。

延迟debounce,示意图:
在这里插入图片描述
前缘debounce, 示意图:
在这里插入图片描述

——图片来源:https://blog.csdn.net/hupian1989

       1.1、应用场景
       (1)监听浏览器窗口的resize、scroll事件事件(不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,只执行最后一次);
       (2)带有Ajax请求的input上输入实时搜索事件(只在用户停止输入时才发送请求);
                。。。。。。
       1.2、实现防抖
       未使用防抖之前:
在这里插入图片描述
       使用防抖之后:
在这里插入图片描述

<!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>debounce</title>
    <style>
      #test {
        height: 150px;
        line-height: 150px;
        text-align: center;
        color: #fff;
        background-color: #ccc;
        font-size: 80px;
      }
    </style>
  </head>
  <body>
    <div id="test">感应区</div>
    <!-- <script>
      function debounce(fn, wait) {
        let timer
        return function () {
          let context = this
          let args = arguments
          //清除上一次延时器
          if (timer) clearTimeout(timer)
          //重新设置新的延时器
          timer = setTimeout(() => {
            fn.apply(context, args)
          }, wait)
        }
      }

      function debounce(fn, wait) {
        let timer
        return function () {
          let context = this
          let args = arguments

          //清除上一次延时器
          if (timer) clearTimeout(timer)

          let callNow = !timer
          timer = setTimeout(() => {
            timer = null
          }, wait)

          if (callNow) fn.apply(context, args)
        }
      }

      document.getElementById('btn').onclick = debounce(function () {
        console.log('debounce被触发了')
      }, 1000)
    </script> -->

    <script>
      /**
       * @param fn 需要执行的函数
       * @param wait 延迟执行时间(毫秒)
       * @param immediate true立即执行,false非立即执行
       **/
      function debounce(fn, wait, immediate) {
        //记录上一次延时器
        let timer
        return function () {
          //this指向debounce
          let context = this
          //参数,fn,wait
          let args = arguments

          //如果timer不为null, 清除定时器
          if (timer) clearTimeout(timer)

          //立即执行
          if (immediate) {
            var callNow = !timer
            //定义wait时间后把timer变为null
            timer = setTimeout(() => {
              timer = null
            }, wait)
            //如果callNow为true,执行fn函数
            if (callNow) fn.apply(context, args)
          } else {
            //不立即执行,就每次重新定时
            timer = setTimeout(function () {
              fn.apply(context, args)
            }, wait)
          }
        }
      }

      let num = 0
      function count() {
       num++
       console.log(num);
      }
      document.getElementById('test').onmousemove = debounce(count,1000,false)
      
    </script>
  </body>
</html>

       1.3、哪里有现成的工具?

lodash 里面有:

_.debounce(func, [wait=0], [options={}])

underscore 里面也有:

_.debounce(function, wait, [immediate])

       2、throttle(节流)
        策略:在固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。 节流策略也分前缘和延迟两种。与debounce类似,延迟是指 周期结束后执行动作,前缘是指执行动作后再开始周期。
        简单来说,对多次触发事件的函数,在规定时间内,只执行一次 。
延迟throttle,示意图:
在这里插入图片描述
前缘throttle, 示意图:
在这里插入图片描述

——图片来源:https://blog.csdn.net/hupian1989

       2.1、应用场景
       (1)下拉加载更多(无限滚动)事件(是否滑到底部自动加载更多);
       (2)鼠标连续不断地触发某事件(如点击,只在单位时间内只触发一次);
                。。。。。。
       2.2、实现节流
       节流一般有两种方式可以实现,分别是时间戳版定时器版
       时间戳版:

function throttle(fn, wait) {
    let previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            fn.apply(context, args);
            previous = now;
        }
    }
}

       定时器版:

function throttle(fn, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                fn.apply(context, args)
            }, wait)
        }

    }
}

       2.3、应用示例
       示例:
在这里插入图片描述

<!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>throttle</title>
    <style>
        html,body{
            height: 500%;
        }
    </style>
</head>
<body>
    <script>
        function throttle(fn,delay){
            var lastTime = 0;
            
            return function(){
                var nowTime = Date.now();
                
                if(nowTime - lastTime>delay){
                    fn.call(this);
                    lastTime = nowTime;
                }
            }
        }
        
        document.onscroll = throttle(function(){
            console.log('scroll被触发了'+Date.now());
        },1000)

    </script>
</body>
</html>

       2.4、哪里有现成的工具?
       lodash 里面有:

_.throttle(func, [wait=0], [options={}])

       underscore 里面也有:

_.throttle(function, wait, [options])

       根据不同场景选择合适的用法。对于有停顿的高频触发事件建议选择防抖,对于高频触发并且连续的事件,选择节流。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值