js 函数防抖与节流

前言

我们为什么需要函数防抖与节流

我们在实际开发当中,可定会遇见持续触发的事件如:onmousemoveonchangeresize等这种持续触发的事件,我们还可能会遇见那么持续需要点击的功能:抽奖点击购买商品等功能

以上这种情况都会引出来一个问题,那就是页面可能会卡顿,性能较低等问题

那么我们可以通过函数节流和函数防抖等我们人为定义函数功能的方式来解决这种问题

什么是函数防抖与节流

举个栗子,当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会形成一个连贯的动画,所以在电影的播放中基本是以每秒 24 张的速度播放的,为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候,100 张就会显得很浪费资源

再举个栗子,假设电梯一次只能载一人的话,10 个人要上楼的话电梯就得走 10 次,是一种浪费资源的行为;而实际生活正显然不是这样的,当电梯里有人准备上楼的时候如果外面又有人按电梯的话,电梯会再次打开直到满载位置,从电梯的角度来说,这时一种节约资源的行为(相对于一次只能载一个人)。

  • 函数节流: 指定时间间隔内只会执行一次任务;
  • 函数防抖: 任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。

函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流。
函数去抖就是对于一定时间段的连续的函数调用,只让其执行一次。

应用场景

函数节流(throttle)应用场景

函数节流有哪些应用场景?哪些时候我们需要间隔一定时间触发回调来控制函数调用频率?

  • DOM 元素的拖拽功能实现(mousemove
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 计算鼠标移动的距离(mousemove
  • Canvas 模拟画板功能(mousemove
  • 搜索联想(keyup

函数防抖(debounce)应用场景

函数去抖有哪些应用场景?哪些时候对于连续的事件响应我们只需要执行一次回调?

  • 每次 resize/scroll 触发统计事件
  • 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,验证一次就好)

在这里插入图片描述

函数节流和函数防抖的核心其实就是限制某一个方法被频繁触发,而一个方法之所以会被频繁触发,大多数情况下是因为 DOM 事件的监听回调,而这也是函数节流以及防抖多数情况下的应用场景。

实现

实现函数防抖

<script>
  /*
   *  函数防抖
   *   在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。
   **/
   // technique防抖函数:接收的形参 fn函数 time时间
   function technique(fn, time) {
      let resultTime = null // 定时器的返回值(用于清除定时器)
      return function (...args) { // 返回一个函数并且扩展出一些参数
          clearTimeout(resultTime) // 清除定时器
          // 执行定时器 并且该变fn函数的this指向和设置time的时间
          resultTime = setTimeout(fn.bind(this, ...args), time)
      }
   }
   // 使用
   const resultFn = technique(function (e) {
         console.log('执行', this, e);
   }, 1000)
   document.addEventListener('click', resultFn)
</script>

代码解读

  • 首先我们人为定义一个technique的函数,并且接收两个参数(函数(fn)执行的时间(time)
  • 我们在初始的时候要设置一个变量resultTime来接收我们定时器返回出来的值,用于我们清除上一次定时器
  • 并且我们要return返回出来一个函数并且用扩展运算符来扩展出来一下参数(如事件对象,我们传递过来的参数)
  • 并且我们在执行technique函数的时候需要清除一下我们上一次开启的定时器,并且在开启一个定时器,还需要用bind改变fn函数的this指向问题和传递参数的问题
  • 然后我们就可以在事件当中去应用这个technique防抖函数了

实现函数节流

<script>
    /*
    *  函数节流
    *       连续执行函数,每隔一定时间执行函数。规定一个单位时间,
    *       在这个单位时间内,只能有一次触发事件的回调函数执行,
    *       如果在同一个单位时间内某事件被触发多次,只有一次能生效。
    * */
    // throttle节流函数 接收的参数:fn函数,time时间
    function throttle(fn, time) {
        let start = 0 // 初始函数节流的时间
        return function (...args) { // 返回一个函数并且扩展出一些参数
            const newDate = new Date()  // 获取当前最新的时间
            // 如果最新的时间-节流的时间 >= time我们人为定义节流的时间 那么就执行
            if (newDate - start >= time) {
                start = new Date() // 从新设置初始节流的时间
                fn.call(this, ...args) // 修改this指向并且传递一些参数
            }
        }
    }
    // 应用
    const resultFn = throttle(function (e) {
        console.log('执行', this, e);
    }, 1000)
    document.addEventListener('click', resultFn)
</script>

代码解读

  • 我们先人为定义throttle的函数,并且接收两个参数(函数(fn)执行的时间(time)
  • 我们在定义start变量,用于记录初始的节流时间默认是0即可
  • 我们在返回出去一个函数,并且这个函数的形参需要扩展出来一下参数...args,而在这个函数内部我们在定义一个当前最新的时间变量newDate
  • 在进行if的判断:如果最新的时间(newDate)-节流的时间(start) >= 我们人为定义节流的时间(time),那么我们就从新设置节流的时间start,并且改变fn函数的this执行和传递一些参数
  • 然后我们就可以在事件当中去应用这个throttle节流函数了

应用

应用节流函数

css+html代码

<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    .box {
        position: absolute;
        top: 0;
        left: 0;
        width: 200px;
        height: 200px;
        background-color: pink;
        cursor: pointer;
    }
</style>
<div class="box"></div>

javascript代码

var oBox = document.getElementsByClassName("box")[0]
// 点鼠标点击盒子的时候 触发mousedown事件
oBox.addEventListener('mousedown', function (e) {
    // 并且获取他的clientX和Y值
    var clientX = e.clientX
    var clientY = e.clientY
    // 并且获取他的offsetTop和offsetLeft值
    var offsetTop = this.offsetTop
    var offsetLeft = this.offsetLeft
    // 当鼠标移动的时候触发mousemove事件
    function move(e) {
        // 并且获取他的clientY和X值
        var moveX = e.clientX
        var moveY = e.clientY
        // 并且改变他的left和top值
        oBox.style.left = offsetLeft + moveX - clientX + 'px'
        oBox.style.top = offsetTop + moveY - clientY + 'px'
    }
    // mousemove事件 函数节流 并且传递move函数
    function throttle (fn, time = 100) {
        var start = 0; // 初始节流的时间
        return function (...args) {
            var now = new Date
            if (now - start >= time) {
                fn.call(this, ...args)
                start = now
            }
        }
    }
    var throttleFn = throttle(move, 80)
    // 把函数节流的函数作为mousemove的事件处理函数
    document.addEventListener('mousemove', throttleFn)
    // 当鼠标抬起的时候 清除事件
    oBox.addEventListener('mouseup', function () {
        document.removeEventListener('mousemove', throttleFn)
        oBox.removeEventListener('mouseup', oBox)
    })
})

上面代码我们要实现一个div盒子拖动的效果,我们用到了onmousemove时间,而这个事件是多次触发的一个事件,我们可以用节流函数来优化他,并且我们人为可以设置他的拖拽时间

应用防抖函数

react-hooks代码

// 当触发input框当中的change事件的时候触发该事件处理函数
const handleChange = e => {
    const val = e.target.value
    const result = technique(function () {
        setVal(val) // 设置对应的val值
        getQueryData(val) // 请求对应的数据
        if (!val) { // 如果val值为空那么我们就发送一个[]数组 代表没有获取到数据
            Pubsub.publish('SongList', [])
        }
    }, 20)
    result()
}

technique防抖函数

// 防抖函数
export function technique (fn, time = 1000) {
    let resultTime = null
    return function (...args) {
        clearTimeout(resultTime)
        resultTime = setTimeout(fn.bind(this, ...args), time)
    }
}

这段代码是我在一个react hook项目上面拿到的一段代码,大概的功能是我们输入input框的时候需要使用onchange来实时监测他的value值的变化,并且想后台发起请求来获取对应的歌曲数据,在这个功能上面我们使用了防抖函数来优化他,让他在我们认为定义的时间内去获取歌曲数据的请求

小结

节流和防抖函数主要适用于高频触发的操作,如果对于高频触发的时间我们不加以限制,会导致频繁的页面渲染和或者请求等。影响用户体验,此时我们可以用debounce()throttle()的方式来减少回调被处罚的频率,这样既可以达到我们想要的效果又可以减弱对用户体验的影响。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JS函数防抖节流是两种不同的技术,用于解决类似的问题防抖(debounce)指在一定时间内只执行一次函数,如果在这段时间内再次触发函数,则重新计时。这通常用于用户输入或窗口调整等场景,以防止不必要的计算或请求。 节流(throttle)指在一定时间内只执行一次函数,如果在这段时间内再次触发函数,则忽略。这通常用于限制事件的频率,例如鼠标滚动或网络请求。 总的来说,防抖节流都是为了避免因频繁的事件触发导致的性能问题。 ### 回答2: JS函数防抖节流是两种常用的优化手段,用于控制函数的执行频率,减少不必要的资源消耗。 函数防抖的原理是当事件触发后,不立即执行函数,而是等待一段时间(如1000毫秒),如果在这段时间内没有再次触发该事件,则执行函数;如果在该时间段内再次触发了该事件,则重新计时,等待一段时间后再执行函数函数防抖常用于限制高频率触发的事件,比如输入框中的搜索功能,用户连续输入时,只有在停止输入一段时间后,才会执行搜索操作。这样可以减少请求次数,避免不必要的资源浪费。 函数节流的原理是规定一个单位时间,在这个单位时间内,只能执行一次函数。如果在单位时间内多次触发了该事件,只有第一次触发会执行函数,其他触发会被忽略。函数节流常用于限制高频率触发的事件,比如页面滚动时的加载更多功能,用户快速滚动页面时,只会在固定的时间间隔内触发一次加载更多。 总结来说,函数防抖是等待一段时间后执行函数,期间事件还会重新计时,确保函数只在最后一次触发后执行;而函数节流是按照固定的时间间隔执行函数,不管触发次数多少,只在规定的时间间隔内执行一次函数函数防抖更适合控制高频率触发的事件,而函数节流更适合控制单位时间内触发的次数。 ### 回答3: JS函数防抖节流都是用来控制函数执行频率的技巧,但它们的实现方式和应用场景有所不同。 函数防抖是指在事件触发后,等待一定时间之后再执行函数。如果在这个等待时间内再次触发了该事件,就会重新计时。防抖的主要作用是减少函数执行的频率。常见的应用场景有输入框的关键词搜索,用户在输入过程中频繁触发输入事件,而我们希望用户停止输入后再进行搜索操作。使用函数防抖可以避免用户每输入一个字符都进行搜索,减少服务器负载。 函数节流是指在一定时间间隔内只执行一次函数。相比于函数防抖函数节流更注重于函数执行的间隔时间。如果在指定的时间间隔内多次触发了该函数,只有在间隔时间到达后才会执行函数。常见的应用场景包括页面滚动事件、窗口大小改变事件等。通过函数节流,我们可以控制事件响应的频率,避免过于频繁的函数执行。 总结起来,函数防抖适用于限制函数执行频率,主要用于输入框搜索等场景。而函数节流适用于限制函数连续触发的频率,主要用于页面滚动、窗口大小改变等场景。两者的区别在于对时间的处理方式,一个是等待一段时间后执行,一个是一段时间内只执行一次。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值