JavaScript事件的防抖和节流

函数防抖和节流

函数的防抖和节流在我们的工作中经常会用到,在面试中也经常会出现.因此今天我们来聊聊防抖和节流

首先我们来看下面这张用竖线画成的图:

 

这其中的每一条竖线都代表着一次函数调用(如鼠标mousemove事件,input输入事件等) 正常执行的时候,调用的频率很快.但有时,我们并不需要这么高的频率去调用这个函数.假如这是一个调用后台接口的操作,那么就容易造成网络堵塞,大大的增加服务器的压力 函数防抖的时候,每次调用事件都是在正常执行暂停后一段时间(等你歇菜了我再上) 函数节流的时候,则是每隔一定的时间间隔就触发一次(管你频率那么快,我就保持自己的节奏) 现在我们大致明白函数的防抖和节流是怎么一回事了,接下来我们就来具体的学习下它们

防抖(debounce)

概念

在任务频繁触发的情况下,一个事件在被触发的一段时间后再执行回调,假如在这段时间内又被触发了,则重新开始计时.

应用场景

防抖在我们的日常生活中,也是随处可见.就比如我们平时坐电梯的时候,总是要等到没有人进来了再一小会儿的工夫,电梯门才会关上.而在项目中,防抖的应用场景也是挺多的.当我们在一个搜索框输入内容进行远程搜索的时候,往往就是在我们停下输入的一小刻时间后.前台向服务器发起了请求来获得匹配的结果.我们甚至于可以将防抖的过程,看成一个英雄在技能读条,只有技能读条结束了,技能才能扔出来.要是中途被人打断了,那么下次又要重新读条了.

简易版

<input id="ipt1" />

我们先来看下没有防抖的效果:

let ipt1 = document.querySelector('#ipt1')
ipt1.onkeydown = function(e){
    console.log(e.target.value)
}

再来看一下加了防抖效果的代码

let ipt1 = document.querySelector('#ipt1')
let timer = null
ipt1.onkeydown = function(e){
    clearTimeout(timer)
    timer = setTimeout(() => {
        console.log(e.target.value)
    },500)
}

大家可以将代码copy到编辑器中运行一下看看效果,是不是加了防抖效果的用户体验会更好

函数版

<div id="div1"></div>
#div1 {
  height: 300px;
  background-color: orange;
  overflow: auto;
}
let div1 = document.querySelector('#div1')
function move(e){
  this.innerText = `${e.offsetX},${e.offsetY}`
}
function debounce(fn, wait){
  let timer = null
  return function(){
    let args = arguments
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}
let debounceMove = debounce(move, 500)
div1.onmousemove = debounceMove

其中debounce就是我们的核心防抖函数了

节流(throttle)

概念

高频事件触发,但是在n秒内只会执行一次,会稀释函数的执行频率

应用场景

节流在生活中的实例,就比如看电影的时候,每秒有24帧.大概意思就是每一秒钟的电影,其实是给大家播放了24张连续的图片.帧数越高,电影看着就越流畅.但是当帧数达到一定的高度时,我们的肉眼已经是看不出区别了.而在项目当中的应用也较多,比如在滚动加载更多的时候,在监听滚动条位置的时候并不是用户每次滚动都要去监听滚动条的位置,而是例如在1s内不管滚动多少次,只监听一次滚动条的位置.假如将节流运用到游戏当中,那就相当于技能的CD,CD没到,你就是按坏了键盘,技能也放不出来.

简易版

<div id="div1">
    <p>1</p>
    <p>1</p>
    ...
</div>
#div1 {
    height: 200px;
    background-color: orange;
    overflow: auto;
}

我们先来看下普通的效果,可以看到控制台在疯狂输出

let div1 = document.querySelector('#div1')
div1.onscroll = function(e){
    console.log('我在疯狂输出')
}

再来看下加了节流效果的,控制台每隔一段时间才会打印一次内容

let div1 = document.querySelector('#div1')
let flag = true
div1.onscroll = function(e){
    if(!flag){
        return false
    }
    flag = false
    setTimeout(() => {
        console.log('我在慢慢输出')
        flag = true
    },500)
}

函数版

定时器版本

使用定时器来达到节流的效果

let div1 = document.querySelector('#div1')
function move(e){
  this.innerText = `(${e.offsetX}, ${e.offsetY})`
}
function throttle(fn, wait){
  let timer = null
  return function(){
    let args = arguments
    if(!timer){
      timer = setTimeout(() => {
        timer = null
        fn.apply(this, args)
      }, wait)
    }
  }
}
let throttleMove = throttle(move, 500)
div1.onmousemove = throttleMove 

时间戳版本

使用时间戳来达到节流的效果

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

这个版本的时间戳节流当我们的鼠标移出监听区域的时候,即停止运行了.

定时器+时间戳版本

下面我们来个加强版本的,这个版本是结合了定时器和时间戳,在我们鼠标移出监听区域后,还会再执行一次函数

function throttle(fn, wait){
  let time = 0, timer = null
  return function(){
    let now = Date.now()
    let args = arguments
    if(now - time > wait){
      fn.apply(this, args)
      time = now
    }else{
      timer && clearTimeout(timer)
      timer = setTimeout(() => {
        fn.apply(this, args)
        time = now
      }, wait)
    }
  }
}

总结: 防抖和节流都是为了限制函数的执行频率,以优化函数触发频率过高导致的响应速度跟不上,延迟假死或卡顿的现象

  • 函数防抖:原理是维护一个计时器,在规定时间后执行回调.若在此期间再次触发,则重新开始计时
  • 函数节流:原理是判断是否达到规定时间
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
防抖节流是优化 JavaScript 代码性能的两个重要技术,它们可以控制函数的执行频率,从而提高代码的响应速度和性能。下面是用 JavaScript 实现防抖节流的示例代码: ## 防抖 防抖可以控制一个函数在一段时间内只执行一次,常用于输入框搜索、滚动加载等场景。以下是一个基本的防抖函数实现: ```javascript function debounce(func, delay) { let timerId; return function(...args) { if (timerId) { clearTimeout(timerId); } timerId = setTimeout(() => { func.apply(this, args); timerId = null; }, delay); }; } ``` 这个函数接收两个参数,第一个参数是要进行防抖处理的函数,第二个参数是等待时间。该函数返回一个新的函数,每次调用这个新的函数时,会启动一个计时器,等待指定的时间后才会执行传入的函数。 例如,假设我们有一个搜索函数 search(),需要防抖处理,等待 500 毫秒后执行。可以这样调用: ```javascript const debouncedSearch = debounce(search, 500); input.addEventListener('input', event => { debouncedSearch(event.target.value); }); ``` 上面的代码将输入框的输入事件绑定到 debouncedSearch 函数上,每次输入事件发生时,debouncedSearch 函数会启动一个计时器,等待 500 毫秒后才会调用 search 函数。如果在 500 毫秒内再次输入事件发生,计时器会被重置,等待时间重新开始计算。 ## 节流 节流可以控制一个函数在一段时间内最多执行一次,常用于滚动事件、resize 事件等场景。以下是一个基本的节流函数实现: ```javascript function throttle(func, delay) { let timerId; return function(...args) { if (timerId) { return; } timerId = setTimeout(() => { func.apply(this, args); timerId = null; }, delay); }; } ``` 这个函数接收两个参数,第一个参数是要进行节流处理的函数,第二个参数是等待时间。该函数返回一个新的函数,每次调用这个新的函数时,会启动一个计时器,如果计时器已经启动,就直接返回,否则会等待指定的时间后才会执行传入的函数。 例如,假设我们有一个图片懒加载函数 lazyLoad(),需要节流处理,等待 200 毫秒后执行。可以这样调用: ```javascript const throttledLazyLoad = throttle(lazyLoad, 200); window.addEventListener('scroll', throttledLazyLoad); ``` 上面的代码将滚动事件绑定到 throttledLazyLoad 函数上,每次滚动事件发生时,throttledLazyLoad 函数会启动一个计时器,等待 200 毫秒后才会调

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值