一文教你彻底学会JavaScript手写防抖节流

 更新时间:2022年11月30日 10:04:37   作者:快跑啊小卢_  
其实防抖和节流不仅仅在面试中会让大家手写,在实际项目中也可以起到性能优化的作用,所以还是很有必要掌握的。本文就带大家彻底学会JavaScript手写防抖节流,需要的可以参考一下

前言

  • 前段时间群友说面试的时候老是分不清防抖和节流。
  • 其实防抖和节流不仅仅在面试中会让大家手写,在实际项目中也可以起到性能优化的作用,所以还是很有必要掌握的。
  • 接下来我就用一杯茶的时间带大家彻底学会手写防抖和节流。

防抖

个例子

我们先抛开概念不谈,其实在生活中也有很多防抖的例子:

  • 比如你现在使用的电脑,在不使用后一段时间自动休眠
  • 当你再次使用的时候重新激活,并开始你设置的时间倒计时10分钟
  • 在这10分钟内你继续使用电脑又会重新开始倒计时10分钟
  • 当你最后一次使用电脑并离开时重新倒计时10分钟过去了,电脑就休眠了

这其实这就是防抖的基本概念了~说白了就是在一段时间只执行一次,也就是我们上面的电脑只打开这一次。

我们上面的使用电脑可以理解为触发事件,而与我上面标注的setTimeoutclearTimeout其实就是防抖的主要要素了。

当然上面的是生活中的例子,那我们在我们的日常开发中其实也经常用到,比如我们调整页面的大小,验证表单某个字段是否重复时发生请求次数控制,防止表单多次提交等。

手写防抖

说了这么多,相信大家大概理解了防抖的概念,那我们现在来实现一个防抖吧,假设我们要点击一个按钮新增一条信息,当然我们不希望每次点击都调用接口新增,我们希望多次点击只新增一次,这时候我们该怎么写呢?

首先我们先简单的模拟一个按钮被点击的过程。

// debounce.js
let addBtn=document.getElementById('add')
function addOne(){
  console.log('增加一个')
}
addBtn.addEventListener('click',addOne)

因为我们需要对执行的事件进行处理所以接下来我们需要封装一下addOne函数。

// debounce.js
let addBtn=document.getElementById('add')
function addOne(){
  console.log('增加一个')
}
function debounce(fun){
  return function(){
    fun()
  }
}
addBtn.addEventListener('click',debounce(addOne))

上面我们用闭包处理了一下addOne函数,接下来我们需要添加一个延时器setTimeout来倒计时,当我们点击按钮后过2s再执行。

// debounce.js
function debounce(fun,time){
  return function(){
    setTimeout(()=>{
      fun()
    },time)
  }
}
addBtn.addEventListener('click',debounce(addOne,2000))

现在延时的目的是达到了但是每次点击都会新增一个新的setTimeout而且并不能达到我们多次点击只执行一次的效果。

这时候就需要clearTimeout登场了,我们需要在我们点击了按钮后也就是debounce执行时要先把之前的setTimeout先清除再重新计时。

function debounce(fun,time){
  let timer
  return function(){
    clearTimeout(timer)
    timer=setTimeout(()=>{
      fun()
    },time)
  }
}

现在我们的一个防抖功能就完成了,但是这还没完,如果我们在addOne()打印this会发现我们这样执行的this是指向Window的。

这当然不是我们所希望的,我们需要使用apply来改变this指向,再者就是我们需要考虑到执行函数的参数,因为不同的函数肯定会有不同的参数传入,对于参数我们可以使用arguments处理。

function debounce(fun,time){
  let timer
  return function(){
    clearTimeout(timer)
    let args = arguments
    timer=setTimeout(()=>{
      fun.apply(this,args)
    },time)
  }
}

这样我们的防抖函数就手写完成了,看起来其实也并不难。

总而言之防抖就是在不断的操作中(输入、点击等)最终只执行一次的一种提高性能的方法

节流

举个例子

当然我们生活中也会有很多节流的的例子,不知道大家有没有留意过公园的洒水机:

  • 一般我们会给洒水机设定一个时间假设30min
  • 当距离上次洒水时间未够30min的时候一直保持静止状态
  • 而当到了30min则会触发洒水的事件

  • 这其实也是节流的最基本的概念了,说白了就是在间隔一段时间执行一次
  • 我们上面的洒水可以理解为触发事件,而我们上面标注的其他信息也就只有30min和当前时间,这两个就是节流的主要要素了。
  • 当然上面的是我们的生活中的例子,那我们在我们的日常开发中其实也经常用到,比如我们滚动鼠标滚轮监听滚动条位置,防止按钮多次点击等。

手写节流

说了这么多,相信大家大概理解了节流的概念,那我们现在来实现一个节流吧,假设我们现在要实现一个鼠标滚动打印事件,想让它在3s执行一次,这时候我们该怎么写呢?

首先我们先模拟一个触发事件。

// throttle.js
function scrollTest(){
  console.log('现在我触发了')
}
document.addEventListener('scroll',scrollTest)

接下来我们封装一个节流函数,跟防抖一样我们也需要利用闭包,顺便再加一个参数接收节流时间。

// throttle.js
...
function throttle(fun,time){
  return function(){
    fun()
  }
}
document.addEventListener('scroll',throttle(scrollTest,3000))

因为我们的节流是在一段时间内执行一次也就是说如果两次鼠标滚动的时间间隔未到所设置的时间则不执行

那我们可以记录一下每次滚动的时间戳来进行对比。

// throttle.js
...
function throttle(fun,time){
  let t1=0 //初始时间
  return function(){
    let t2=new Date() //当前时间
    if(t2-t1>time){
      fun()
      t1=t2
    }
  }
}

我们会记录两个时间一个是t1代表初始时间一个是t2代表当前时间,如果当前时间距离上一个时间也就是初始时间大于所设置的time

那我们就可以执行fun()并且把初始时间变更为这一次执行的时间,这样每次我们执行过后t1就变成了上一次执行的时间。

这样我们的一个节流功能就完成了。

// throttle.js
...
function throttle(fun,time){
  let t1=0 //初始时间
  return function(){
    let t2=new Date() //当前时间
    if(t2-t1>time){
      fun()
      t1=t2
    }
  }
}

当然我们也需要像防抖一样改变this指向和接收参数,最后完成后是这样的。

// throttle.js
...
function throttle(fun,time){
  let t1=0 //初始时间
  return function(){
    let t2=new Date() //当前时间
    if(t2-t1>time){
      fun.apply(this,arguments)
      t1=t2
    }
  }
}

至此一个节流函数就手写完成了,是不是也不会很难呢?

总而言之节流就是在一段时间内不断操作而在你规定的时间内只执行一次的一种提高性能的方法

写在最后

  • 首先还是很感谢大家看到这里,这次的文章就分享到这里~
  • 对于防抖和节流一个最主观的判断方法就是:在10s内你疯狂点击一个按钮,如果使用了防抖则会只执行一次,而你使用了节流则会每隔一段时间执行一次,这个时间可以自己来掌控。
  • 当然防抖和节流的变形还是有很多的,根据不同的需求来变换不同的函数但是万变不离其宗,只要你搞懂了上面的方法,其他的就没有问题了。

以上就是一文教你彻底学会JavaScript手写防抖节流的详细内容,更多关于JavaScript防抖节流的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript脚本实现解析MyBatis SQL日志

    JavaScript脚本实现解析MyBatis SQL日志

    这篇文章主要为大家详细介绍了如何开发一个简单的 HTML 和 JavaScript 脚本,用于解析 MyBatis 的 SQL 日志并生成可执行的 SQL 语句,需要的可以参考下
    2025-02-02
  • 拖动时防止选中

    拖动时防止选中

    本文主要介绍了拖动时防止选中的小知识点。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • JavaScript 微任务和宏任务讲解

    JavaScript 微任务和宏任务讲解

    这篇文章主要分享了JavaScript 微任务和宏任务讲解,在js中,我们一般将所有的任务都分成两类,一种是同步任务,另外一种是异步任务。而在异步任务中,又有着更加细致的分类,那就是微任务和宏任务,下面来一起学习js中的微任务和宏任务吧
    2021-12-12
  • 教你使用webpack打包编译TypeScript代码

    教你使用webpack打包编译TypeScript代码

    TypeScript同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TypeScript,本文分步骤给大家介绍的非常详细,需要的朋友参考下吧
    2021-06-06
  • 京东优选小程序的实现代码示例

    京东优选小程序的实现代码示例

    这篇文章主要介绍了京东优选小程序的实现代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • 详解JavaScript中ora库的使用教程

    详解JavaScript中ora库的使用教程

    使用 ora 这个 JavaScript 库可以在命令行应用程序中提供漂亮的加载状态提示,本文详细介绍如何使用该库,希望对大家有一定的帮助
    2024-02-02
  • 如何利用JS实现时间轴动画效果

    如何利用JS实现时间轴动画效果

    时间轴动画和帧式动画有很大不同,但相比之下时间轴方式来的更直观和简便,下面这篇文章主要给大家介绍了关于如何利用JS实现时间轴动画效果的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • canvas绘制一个常用的emoji表情

    canvas绘制一个常用的emoji表情

    本文主要介绍了canvas绘制一个常用的emoji表情的示例代码。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-03-03
  • ES6知识点整理之对象解构赋值应用示例

    ES6知识点整理之对象解构赋值应用示例

    这篇文章主要介绍了ES6知识点整理之对象解构赋值应用,结合实例形式分析了ES6对象解构赋值相关概念、原理、出现的问题及相应解决方法,需要的朋友可以参考下
    2019-04-04
  • JavaScript加强之自定义event事件

    JavaScript加强之自定义event事件

    event事件在本文以自定义的方式出现,感兴趣的朋友可以参考下,希望对大家有所帮助
    2013-09-09

最新评论