本文转自:https://www.jianshu.com/p/f9f6b637fd6c

闭包的典型应用就是函数防抖和节流,本文详细介绍函数防抖和节流的应用场景和实现。

函数防抖(debounce)

函数防抖,就是指触发事件后,在 n 秒后只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数的执行时间。

简单的说,当一个动作连续触发,只执行最后一次。

打个比方,坐公交,司机需要等最后一个人进入才能关门。每次进入一个人,司机就会多等待几秒再关门。

函数节流(throttle)

限制一个函数在一定时间内只能执行一次

举个例子,乘坐地铁,过闸机时,每个人进入后3秒后门关闭,等待下一个人进入。

为了方便理解,我们首先通过一个可视化的工具,感受一下三种环境(正常情况、函数防抖情况 debounce、函数节流 throttle)下,对于mousemove事件回调的执行情况。

竖线的疏密代表事件执行的频繁程度。可以看到,正常情况下,竖线非常密集,函数执行很频繁。而 debounce (函数防抖)则很稀疏,只有当鼠标停止移动时,才会执行一次。throttle(函数节流)分布的较为均匀,每过一段时间就会执行一次。

常见的应用场景

函数防抖(debounce)的应用场景

连续的事件,只需触发一次的回调场景有:

  • 搜索框搜索输入。只需要用户最后一次输入完再发送请求
  • 手机号、邮箱格式的输入验证检测
  • 窗口大小的 resize 。只需窗口调整完成后,计算窗口的大小,防止重复渲染。

函数节流(throttle)的应用场景

间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚动到底部监听
  • 谷歌搜索框,搜索联想功能
  • 高频点击提交,表单重复提交
  • 省市信息对应字母快速选择

实现原理

函数防抖(debounce)

简单实现:

const debounce = (func, wait) => {
let timer
return () => {
clearTimeout(timer)
timer = setTimeout(func, wait);
}
}

函数防抖在执行目标方法时,会等待一段时间。当又执行相同方法时,若前一个定时任务未执行完,则 清除掉定时任务,重新定时。

封装:

function debounce(fn, delay = 500) {
// timer 是在闭包中的
let timer = null; return function() {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
} // test debounce 返回一个函数
input1 = document.getElementById('input1')
input1.addEventListener('keyup', debounce(function () {
console.log(input1.value)
}, 600))

绑定事件解释:addEventListener 第一个参数是监听的事件,第二个参数是对应事件的回调函数。将 debounce 函数作为回调函数,这个 debounce 回调函数返回一个防抖之后的函数,因此实现了防抖的功能。

防抖解释:当 按下某个键的时候触发 keydown 事件,并执行回调。timer 默认为 null,在 return 的函数中定时器 timer 被赋值,如果在 delay 延迟之内再次触发了 keydown 事件,那么 timer 就会被重置为null...,当用户输入完成之后(delay 时间已过),那么就会触发 debounce 中的回调函数,也就是 keydown 最终要执行的事件。

函数节流(throttle)

简单实现

const throttle = (func, wait) => {
let timer; return () => {
if (timer) {
return
}
timer = setTimeout(() => {
func();
timer = null
}, wait)
}
}

函数节流的目的,是为了限制函数一段时间内只能执行一次。因此,通过使用定时任务,延时方法执行。在延时的时间内,方法若被触发,则直接退出方法。从而实现一段时间内只执行一次。

封装:

function throttle(fn, delay) {
let timer = null return function() {
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
})
}
}
// test
let div1 = document.getElementById('div1')
div1.addEventListener('drag', throttle(function(e) {
console.log(e.offsetX, e.offsetY)
}, 100))

解释:如果 timer 存在,那就直接返回,不再往下执行了。这样就实现了一段时间内执行一次的目的。

异同比较

相同点:

  • 都可以通过使用 setTimeout 实现
  • 目的都是,降低回调函数的执行频率,节省计算资源

不同点:

  • 函数防抖,是在一段连续操作结束之后,处理回调,利用 clearTimout 和 setTimeout 实现。函数节流,是在一段连续操作中,每一段时间只执行一次,在频率较高的事件中使用来提高性能。
  • 函数防抖关注一段时间内连续触发,只在最后一次执行;而函数节流侧重于在一段时间内只执行一次。

参考资料

详解防抖函数(debounce)和节流函数(throttle)的更多相关文章

  1. Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用

    在上面一个章节中,详细的讲解了Kotlin中关于Lambda表达式的语法以及运用,如果还您对其还不甚理解,请参见Kotlin--高级篇(一):Lambda表达式详解.在这篇文章中,多次提到了Kotli ...

  2. 这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化

    感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 p ...

  3. 函数防抖(Debounce)、函数节流 (Throttle)

    一篇介绍文章:https://zhuanlan.zhihu.com/p/38313717 演示示例:http://demo.nimius.net/debounce_throttle/ 函数防抖(Deb ...

  4. node源码详解(五) —— 在main函数之前 —— js和C++的边界,process.binding

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ...

  5. 转载 :实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(一)

    在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用.虽然Q ...

  6. 详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化

    在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用. 1. ...

  7. 详解php的curl几个函数

    关于php的curl一系列函数,这里解释一下它们的作用. 在html中,我们可以通过form设置http的post和get提交,但假如我们获取的数据不是从html中来的,而是php脚本主动向其他服务器 ...

  8. JavaScript语法详解:if语句&for循环&函数

    本文首发于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. if语句 最基本的if语句 if语句的结构体:(格式) if (条件表达式) ...

  9. 详解递归(基础篇)———函数栈、阶乘、Fibonacci数列

    一.递归的基本概念 递归函数:在定义的时候,自己调用了自己的函数. 注意:递归函数定义的时候一定要明确结束这个函数的条件! 二.函数栈 栈:一种数据结构,它仅允许栈顶进,栈顶出,先进后出,后进先出.我 ...

随机推荐

  1. Mysql备份方案总结性梳理

    Mysql备份方案总结性梳理   服务器 mysql 日志 数据库 配置 Mariadb binlog   mysql数据库备份有多么重要已不需过多赘述了,废话不多说!以下总结了mysql数据库的几种 ...

  2. 20192204-exp1-逆向与Bof基础

    1 逆向及Bof基础实践说明 1.1 实践目标 本次实践使用的是kali系统 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回 ...

  3. CF1428B题解

    打比赛的时候sb了,用了一个似乎原本可以不用的东西来找环... 首先,根据题意,我们可以连成一张图,而蛇能不能回到自己的家, 只需要在一个环上就行了. 问题是怎么找环,我用了 Tarjan... 具体 ...

  4. Python之简单的用户名密码验证

    题目要求: 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定   #要求使用文件存储用户名和密码,每次从文件读入用户名和密码用来验证,如果输错三次密码该账户会被锁定,并讲锁定的用户名写入文件 # ...

  5. 华夏基金X袋鼠云:基金业数字化转型,为什么说用户才是解题答案?

    "精准营销是以客户为中心,运用各种可利用的方式,在恰当的时间,以恰当的价格,通过恰当的渠道,向恰当的顾客提供恰当的产品." 这是学者许瑾在科特勒精准营销理论的基础上,从实践的角度对 ...

  6. Java将彩色PDF转为灰度

    本文以Java代码为例介绍如何实现将彩色PDF文件转为灰度(黑白)的PDF文件,即:将PDF文档里面的彩色图片或者文字等通过调用PdfGrayConverter.toGrayPdf()方法转为文档页面 ...

  7. vue学习过程总结(02)- 网上开源项目vue-element-admin的启动

    1.功能丰富的项目:https://github.com/PanJiaChen/vue-element-admin.git 因为我配置的时候,遇到许多的问题,用了一天半才启动的,所以安着他文档一步一步 ...

  8. java中对集合操作的易错点01

    今天用for循环遍历集合,对集合中满足条件的元素进行remove操作报错:ConcurrentModificationException 所以,在遍历集合进行增.删操作时,要使用迭代器的方式 publ ...

  9. Apache Ranger安装部署

    1.概述 Apache Ranger提供了一个集中式的安全管理框架,用户可以通过操作Ranger Admin页面来配置各种策略,从而实现对Hadoop生成组件,比如HDFS.YARN.Hive.HBa ...

  10. 通过Kuberneters Goat学习K8S安全(上)

    实验环境:https://katacoda.com/madhuakula/scenarios/kubernetes-goat 0x1.敏感信息泄露利用 第一关是代码泄露利用,打开网站后显示: 告诉我们 ...