首页 > 其他分享 >防抖和节流

防抖和节流

时间:2023-04-27 17:56:35浏览次数:34  
标签:function context 防抖 节流 args timeout wait

1.debounce(防抖)和throttle(节流)的定义

口语版:
防抖就是只有当小明连续10天不捣蛋时,小明爸爸才给他零花钱。如果在这10天内小明捣蛋了, 那么重新计算,直到满足了10天不捣蛋的条件,小明爸爸才给零花钱。一年下来小明居然只拿到了5次零花钱,你说气人不?
节流就是无论小明捣蛋不捣蛋,小明爸爸每隔10天都给小明零花钱。一年下来,小明拿到了36次零花钱。
防抖是有条件的周期动作,而节流是没有条件的周期动作。
书面版:
防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。

2.防抖和节流解决什么问题

在进行resize、scroll、keyup、keydown、mousedown、mousemove等事件操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,容易导致页面卡顿等影响用户的体验;这时就可以通过debounce(防抖)和throttle(节流)函数来限制事件处理函数的调用频率,提升用户的体验,同时又不影响实际的效果。

3.防抖和节流的应用场景

防抖
1.登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。
2.调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多。
3.文本编辑器实时保存,当无任何更改操作一秒后进行保存。
4.DOM 元素的拖拽功能实现。
5.计算鼠标移动的距离。
6.Canvas 模拟画板功能。
7.搜索联想。
节流
1.scroll 事件,每隔一秒计算一次位置信息等。
2.浏览器播放事件,每个一秒计算一次进度信息等。
3.input框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)。

4.防抖的代码实现

以scroll事件为例

function scrollHandler() {
  console.log('滚动了')
}
window.addEventListener('scroll', scrollHandler)

效果如下,触发了很多次回调事件:

1.防抖函数的基本实现:

function debounce(fn, wait) {
  var timeout  //闭包的方式定义一个全局变量,是实现防抖函数的核心
  return function () {
    var context = this,
    args = arguments
    clearTimeout(timeout)

    timeout = setTimeout(function () {
      fn.apply(context, args)
    }, wait)
  }
}
window.addEventListener('scroll', debounce(scrollHandler, 500))

理解的难点:
a)逻辑过程是, 定义一个setTimeout事件, 假如在触发之前,又发生了scroll事件的话, 通过clearTimeout函数清除之前定义的setTimeout事件,同时又再次定义一个setTimeout定时事件,从而达到防抖的功能。
b) debounce(scrollHandler, 500),这句代码返回的是一个函数,并没有显式传递参数进去,为什么还要特意用args = arguments这句话特意的接受一下参数, 原因是因为js引擎会自动的传递event事件参数,所以用args = arguments这句话是为了接受event等默认传递的参数。
2.立即执行的版本的防抖函数,刚才的防抖函数是没有立即执行的,也就是触发事件后不会马上执行,但是某些场景下需要立即执行;立即执行后当n秒内触发事件才能再次执行。

function debounce(fn, wait) {
  let timeout, result;
  return function () {
    const context = this
    const args = arguments
    clearTimeout(timeout)
    const callNow = !timeout
    timeout = setTimeout(function() {
      timeout = null
    }, wait)
    if (callNow) result = fn.apply(context, args)
    return result
  }
}

理解了上个版本的基础上,再来理解立即执行版本的防抖函数,应该比较简单,核心就是通过callNow变量及setTimeout函数把timeout置空的方式来决定是否调用回调函数。
3.综合版本,为了更加灵活的使用,适应各种场景。

function debounce(fn, wait, immediate) {
  var timeout, result;
  return function () {
    var context = this
    var args = arguments
    clearTimeout(timeout)
    if (immediate) {
      var callNow = !timeout
      timeout = setTimeout(function () {
        timeout = null
      }, wait)
      if (callNow) result = fn.apply(context, args)
    } else {
      timeout = setTimeout(function () {
        fn.apply(context, args)
      }, wait)
    }
    return result
  }
}

5.节流的代码实现

1.节流函数的基本实现

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

基本的逻辑是对timeout进行判断, 只有为空才能设置setTimeout事件,从而达到了一个周期只执行一次回调函数的功能,不过这个函数,并没有立即执行的功能。
2.立即执行的版本

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

previous初始为0, now-previous肯定大于wait,所以fn函数在一开始就会被触发。一个wait周期之后又会重新触发。
3.综合版

function throttle(fn, wait, immediate) {
  let timeout
  let previous = 0
   reutrn function () {
    let context = this
    let args = arguments
    if (immediate) {
      let now = Date.now()
      if (now - previous > wait) {
        fn.apply(context, args)
        previous = now
      }
    } else {
      if (!timeout) {
        timeout = setTimeout(() => {
          timeout = null
          fn.apply(context, args)
        }, wait)
      }
    }
  }
}

6.总结

函数节流与函数防抖都是为了限制函数的执行频次,都是一种性能优化的方法。区别是防抖是有条件的周期性动作,而节流是无条件的周期性动作。两者实现的核心都依赖于闭包。

来源 | https://zhuanlan.zhihu.com/p/386616278

标签:function,context,防抖,节流,args,timeout,wait
From: https://www.cnblogs.com/0627st/p/17359786.html

相关文章

  • vue2 input防抖功能
    1.在el-input绑定@input事件 2.在data中定义timer为null 3.在methods中定义@input绑定的方法 4.在setTimeout中调用对应处理的方法<el-inputstyle="width:140px;color:#FF8900"size="small"v-model="singleDiscountForm.discount"@input="inputDis......
  • js节流和防抖
    节流(throttle):指连续触发事件的函数,在一定时间间隔内只执行一次。functionthrottle(fn,delay){lettimer=null;returnfunction(){constself=this;constargs=arguments;if(!timer){timer=setTimeout(function(){timer......
  • 防抖和节流及多种实现方式
    当用户在网页中进行操作时,如点击、滚动、输入等,往往会频繁地触发事件。如果每个事件都立即执行相应的函数,可能会导致性能问题和用户体验不佳,因为这些函数可能需要执行复杂的操作,如计算、网络请求等。为了优化这种情况,我们可以使用防抖和节流来限制函数的调用次数,从而提高性能和用......
  • js实现防抖(debounce)与节流(throttle)
    防抖(debounce)一句话概括:防抖是给定一个时间周期,如果触发事件的周期小于该事件(也就是触发过快),则不会触发事件。举个例子:我给定的时间周期是1s,如果我在触发第一次事件后1s内触发该事件,则重新开始计时,直到触发周期大于1s才会执行事件的方法。functiondebounce(fn,timeout){......
  • js-防抖和节流的区别及实现
    函数防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。函数节流(throttle):高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。函数节流(throttle)与函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过......
  • 函数防抖
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=d......
  • JS中的函数防抖
    一、什么是函数防抖概念:函数防抖(debounce),就是指触发事件后,在n秒内函数只能执行一次,如果触发事件后在n秒内又触发了事件,则会重新计算函数延执行时间。举个栗子,坐电梯的时候,如果电梯检测到有人进来(触发事件),就会多等待10秒,此时如果又有人进来(10秒之内重复触发事件),那么电梯就......
  • 手写防抖节流函数
    防抖函数functiondebounce(fn,t){  lettimeId  returnfunction(){//如果有定时器就清除  if(timeId)clearTimeout(timeId)//开启定时器200  timeId=setTimeout(function(){   fn()  },t) }}//节流函数throttlefunctionth......
  • 第二篇 手写原理代码 - 函数【 函数防抖 、函数节流 】
    函数防抖和函数节流都是优化高频事件处理的JavaScript技术。它们可以限制函数的调用,在一定程度上减少计算、网络请求和提高响应速度,但它们的实现方式略有不同函数防抖:延迟执行函数,只有在事件停止后才会执行最后一次事件函数节流:定期执行函数,每隔一段时间执行一次通常情况下,......
  • js优化(防抖和节流)
    ......