欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端面试系列-JavaScript-防抖与节流(用节流优化防抖)

程序员文章站 2022-06-09 21:40:09
...

一.函数防抖

当持续触发事件时,并不执行事件处理函数,一定时间段内没有再触发事件,事件处理函数才会执行一次;如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

function debounce(fn, delay) {
  // 定时器
  let timer = null
  // 将debounce处理结果当作函数返回
  return function () {
    // 保留调用时的this上下文
    let context = this
    // 保留调用时传入的参数
    let args = arguments
    // 每次事件被触发时,都去清除之前的旧定时器
    if(timer) {
        clearTimeout(timer)
    }
    // 设立新定时器
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}

二、函数节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

1.时间戳实现

function throttle(fn, interval) {
      // last为上一次触发回调的时间
      // 对比时间戳,初始化为0则首次触发立即执行,初始化为当前时间戳则wait毫秒后触发才会执行
      let last = 0;
      // 将throttle处理结果当作函数返回
      return function () {
          // 保留调用时的this上下文
          let context = this
          // 保留调用时传入的参数
          let args = arguments
          // 记录本次触发回调的时间
          let now = Date.now();
          
          // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
          if (now - last >= interval) {
          // 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
              last = now;
              fn.apply(context, args);
          }
        }
    }

2.定时器实现

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

3.用节流优化防抖(定时器+时间戳)

防抖的问题在于如果用户的操作十分频繁——他每次都不等 设置的 delay 时间结束就进行下一次操作,于是每次都为该用户重新生成定时器,回调函数被延迟了不计其数次。 频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。

用节流来优化,保证在一定时间段内会调用一次事件处理函数。

 function throttle(fn, delay) {
       // last为上一次触发回调的时间, timer是定时器
       let last = 0, timer = null
       // 将throttle处理结果当作函数返回
       
       return function () { 
         // 保留调用时的this上下文
         let context = this
         // 保留调用时传入的参数
         let args = arguments
         // 记录本次触发回调的时间
         let now = +new Date()
        // +是一元操作符,利用js隐式转换将其他类型变为数字类型
         
         // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
         if (now - last < delay) {
         // 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
            clearTimeout(timer)
            timer = setTimeout(function () {
               last = now
               fn.apply(context, args)
             }, delay)
         } else {
             // 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
             last = now
             fn.apply(context, args)
         }
       }
     }

三、总结

  • 函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
  • 函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
  • 区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。
  • 场景:比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

四、例子

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>

<body>

</body>
<script>
    // JS的节流与防抖
    //用节流优化防抖 (定时器+时间戳)

    function throttle(fn, delay) {
        let last = 0,
            timer = null
        return function () {
            // 保留调用时的this上下文
            let context = this
            // 保留调用时传入的参数
            let args = arguments
            // 记录本次触发回调的时间
            let now = +new Date()
            // +是一元操作符,利用js隐式转换将其他类型变为数字类型
            // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
            if (now - last < delay) {
                // 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
                clearTimeout(timer)
                timer = setTimeout(function () {
                    last = now
                    fn.apply(context, args)
                }, delay)
            } else {
                // 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
                last = now
                fn.apply(context, args)
            }
        }
    }

    // 用新的throttle包装scroll的回调
    const better_scroll3 = throttle(() => console.log('防抖+节流,触发了滚动事件'), 1000)
    document.addEventListener('scroll', better_scroll3)
</script>

</html>

本文链接:https://blog.csdn.net/qq_39903567/article/details/115154129