目录

  • JavaScript中的节流和防抖
  • 节流和防抖的区别
  • 使用场景
  • 实现节流和防抖
    • 防抖
    • 节流

JavaScript中的节流和防抖

你是否因过度调用函数而影响性能呢?

解决性能问题是在 JavaScript 应用中经常要面对的事情。

节流和防抖使我们能够控制函数调用的速度,这是任何 Web 开发人员都需要了解的技术。当我们为事件绑定事件处理程序时,它们非常有用。在某些场景中,我们没有必要调用函数。 想一想我们要在 window 的 resize 事件触发时执行一个回调,每当浏览器的窗口尺寸变化时就要执行回调真的有意义吗?很可能不是,我们希望等待用户完成交互之后,再执行回调。

这儿有一个 demo(在窗口中对 mousemove 和 touchmove 事件处理程序做节流和防抖处理。节流函数调用 用红色菱形表示,防抖函数调用 用绿色圆圈表示):https://codepen.io/jh3y/pen/mGVGvm

节流和防抖的区别

节流 throttle:

throttle 是英文风门、油门、节流阀的意思。我们可以想到,通过脚踩油门可以控制进入发动机的油量,像这种操作一样,某些情况我们希望控制函数调用的次数。

我们找一个更好的类比,节流就像是乐透(彩票)一样,每五秒钟只出一个球。

或许更好的类比是在酒吧喝酒,你去了一个酒吧,但是在这儿有个规矩,每隔45分钟才能续杯一次。你在第一分钟点了一杯酒然后服务员递给你一杯,然后你想每隔一分钟就喝一杯,但是老板不让你这么做,直到45分钟后才给你下一杯,所以你必须等到45分钟后你才能喝下一杯。

使用节流时,我们可能希望节流结束时进行最后一次调用。想象一下,你在第15分钟点了一杯酒然后被拒绝,在第45分钟时你没有点,但是因为有第15分钟的一个订单给你上了一杯,老板对你感到抱歉?

节流是一个高阶函数,接收一个函数和一个超时参数。节流能控制函数在指定时间间隔内只被调用一次。它的作用是可以减慢函数调用

防抖 debounce:
**
防抖解释起来可能有点困难,就像在餐厅点餐,你向服务员说出要吃的东西,最后她会问你还需要其他的吗,如果你确定这些已经足够了不需要其他的了她们才会离开去给你准备,如果你还需要的话就继续向订单中添加东西,最后她们还问你还需不需要其他的,知道你确定已经足够了。

防抖和节流不同,使用防抖时,直到用户停止操作才会触发函数调用。它常被用在用户完成键入或滚动时要执行计算或调用接口的场景

一句话总结:

节流是限制流量,点击次数再多,短时间内有效的也只有一次;防抖是防止手抖,连续多点了几次,也只是最后一次有效。

微信群中有人这么说:节流就跟怀孕一样,一段时间内只能怀一胎;防抖就跟下班一样,只要有新活儿来就不能走。

上边 Codepen 中节流和防抖的可视化演示,可能有助于理解,移动鼠标或滑动手指(移动端)开始执行节流和防抖

使用场景

  • 用户可能连续点击时使用节流

  • API 调用时使用节流

  • mousemove 或 touchmove 事件回调时使用节流

  • resize 事件回调时使用防抖

  • scroll 事件回调时使用防抖

  • 一个自动保存功能中,保存函数使用防抖

让我们思考每一个场景,节流可能比防抖用的少。通常情况下,当你考虑使用节流时,可能使用防抖更好

对于节流,让我们看第一个例子,用户可能连续点击时使用节流。我们的应用中有一个按钮,当点击按钮时,就会调用某个 API,通过节流就可以限制 API 的调用次数。用户可能每秒钟点击20次,但我们每秒钟只触发一次回调

对于防抖,可以看自动保存功能的例子。每次用户进行更新或交互操作时,自动保存函数都尝试保存应用状态。这时我们可以使用防抖,直到用户在一段时间内没有进行任何更新或交互操作,才进行保存。这样就能避免用户连续操作时进行过多不必要的保存,有利于提高性能

实现节流和防抖

节流和防抖有各种不同的实现,但最终的目标都是一样的,大部分实现中都使用了 setTimeout

https://codepen.io/jh3y/pen/opNYWy 在这个例子中,函数以2秒时间进行防抖限制、以3秒时间进行节流限制

防抖

在两者中,防抖实现起来较为简单

const debounce = (func, delay) => {let inDebouncereturn function() {const context = this // 保存传给新函数的 thisconst args = arguments // 保存传给新函数的参数clearTimeout(inDebounce) // 清空上次调用inDebounce = setTimeout(() => func.apply(context, args), delay) // 重新计时,delay 时间后调用原函数,传入了已保存的 this 和参数}
}

将函数(func)和延迟时间(delay)传递给防抖函数,inDebounce 是执行函数的定时器的引用,这里是一个闭包

如果我们是第一调用,函数将在延迟结束时(也就是 delay 毫秒)执行。如果我们我们在延迟结束之前(也就是 delay 毫秒内)再次调用,则会重新计时,在重新计时后的 delay 毫秒执行

下面是使用防抖的例子:

debounceBtn.addEventListener('click', debounce(function() {console.info('Hey! It is', new Date().toUTCString());
}, 3000));

在这个例子中,停止点击按钮3秒后,会打印时间

节流

节流的实现有点复杂,因为节流的操作有不同的解释。让我们从限制执行函数的速度开始

const throttle = (func, limit) => {let inThrottlereturn function() {const args = argumentsconst context = thisif (!inThrottle) {func.apply(context, args)inThrottle = truesetTimeout(() => inThrottle = false, limit)}}
}

第一次调用我们的函数将立刻执行并设置 inThrottle 为 true,表示正在节流中。如果在 limit 时间内再次调用节流函数,因为此时 inThrottle 为 true,原函数不会执行。当 limit 时间后,将 inThrottle 置为 false。

因为 limit 时间后 inThrottle 为 false,所以再调用时就像第一次调用一样,然后不断重复这个过程。

使用节流的例子:

throttleBtn.addEventListener('click', throttle(function() {return console.log('Hey! It is', new Date().toUTCString());
}, 1000));

但是最后一次调用怎么办呢?在这样的场景中:通过点击 div 的四个角然后绑定鼠标的 mousemove 事件来控制 div 的大小,为了避免过多计算提高性能,我们使用了上边 throttle 的实现,并且将限制时间 limit 设为500ms,如果我们拖动鼠标很快,比如从开始拖动到结束拖动只用了400ms,但是在上边的实现中,只会在刚开始拖动的时候触发一次函数通过鼠标位置计算 div 大小,在结束的 400ms 时却没有触发,所以这个实现并不能100%得到预期的结果。因此我们需要在限制时间 limit 内获取到最后一次函数调用并执行它。

下面是修改后的节流函数:

const throttle = (func, limit) => {let Timerlet lastRanTimereturn function() {const context = thisconst args = argumentsif (!lastRanTime) { // 第一次调用func.apply(context, args) // 直接传参执行原函数lastRanTime = Date.now() // 并记录执行时间} else {clearTimeout(Timer) // 清除上次调用Timer = setTimeout(function() { // 保存这次调用的引用if ((Date.now() - lastRanTime) >= limit) {func.apply(context, args)lastRanTime = Date.now()}}, limit - (Date.now() - lastRanTime)) // 保证每一个 limit 时间段内的最后一次调用都会执行}}
}

这个实现确保我们获取并执行最后一次调用,并且调用的时间(每个 limit 时间段的结尾)也是正确的。我们通过一个变量 lastRanTime 来实现,该变量保存最后一次调用的时间戳,然后根据它确定最后一次调用是否发生在 limit 范围内。我们也使用了 lastRanTime 来确定是否运行了该节流函数,所以之前实现中的 inThrottle 变量就不需要了

总之,防抖和节流都是我们需要了解的技术,它们可以显著的提高应用的性能。

【译】JavaScript 中的节流(throttle)和防抖(debounce)相关推荐

  1. JavaScript 函数节流 throttle 和防抖 debounce

    今天和别人聊到JavaScript函数的节流和防抖,发现自己对这两个的区别很是模糊,遂小小实践一下,在此记录,希望对需要的人有所帮助. 节流 - 频繁操作,间隔一定时间去做一件事 举例说明:假定时间间 ...

  2. 【前端帮帮忙】第7期 关于节流(throttle)和防抖(debounce)的理解

    节流和防抖在我们平时的项目中挺常用的,也是面试中经常会被提问的知识点,今天我们一起来学习一下. 节流 简单理解就是:控制函数每隔n秒执行一次. 作用 防止用户高频率的触发事件,刚好这个事件又需要处理大 ...

  3. 事件触发控制_前端性能优化:事件的节流throttle与防抖debounce

    scroll 事件是一个非常容易被反复触发的事件,另外,resize 事件.鼠标事件(比如 mousemove.mouseover 等).键盘事件(keyup.keydown 等)都存在被频繁触发的风 ...

  4. 节流(Throttle)和防抖(Debounce)

    为啥要使用防抖和节流 在项目开发中,我们经常用到的滚动事件或者用户输入事件,都是一些高频事件,如果对这类事件触发的频率没有节制,就会加重浏览器和服务器的负担.节流和防抖目的就是减少事件触发的次数. 1 ...

  5. [译] JavaScript 中的 CSS:基于组件的样式的未来

    本文讲的是[译] JavaScript 中的 CSS:基于组件的样式的未来, 原文地址:CSS in JavaScript: The future of component-based styling ...

  6. vue项目中使用节流throttle

    问题描述 用户短时间快速点击,向后台发起多次请求 项目中有如图所示弹窗,用户编辑完成之后,快速点击确定,进行保存. 列表中会展示刚才保存的数据,可以看到出现了重复的数据.虽然后端已经加了参数名不能重复 ...

  7. [译]JavaScript中,{}+{}等于多少?

    最近,Gary Bernhardt在一个简短的演讲视频"Wat"中指出了一个有趣的JavaScript怪癖:在把对象和数组混合相加时,会得到一些你意想不到的结果.本篇文章会依次讲解 ...

  8. [译]Javascript中的闭包(closures)

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  9. [译]JavaScript中的属性:定义和赋值的区别

    原文:http://www.2ality.com/2012/08/property-definition-assignment.html 你知道吗?定义一个属性和为一个属性赋值是有区别的.本文解释了两 ...

最新文章

  1. Windows Server2008R2 域迁移
  2. 关闭window端口445
  3. 扇区示意图计算机组成原理,计算机组成原理本.ppt
  4. Pandas的学习(2.Series的索引和切片、基本概念以及Series的运算)
  5. 【2018.5.19】模拟赛之四-ssl2435 航空公司【并查集,二分】
  6. 基于java的数据结构学习——泛型动态数组的封装
  7. Java实现文件夹打包
  8. opengl学习笔记(六)
  9. iPhone XR 2再曝新配色:清新自然 是原谅的味道?
  10. windows server 2019添加开机启动项
  11. 电流转电压的multisim仿真电路图
  12. 卡方检验四格表怎么做_SPSS案例实践:2*2四格表卡方检验
  13. win 7更改计算机用户名和密码错误,解决win7一开机就显示用户名和密码错误故障...
  14. 招银网络 Java后端面经
  15. Golang的Redis简单使用及集群配置(Win10)
  16. 用SAXReader解析xml文档
  17. qps多少才算高并发_要大到什么程度?才算高并发?
  18. WebSocket 初识篇
  19. c语言编程一个 图书管理,我也要用c语言编程一个图书管理系统,
  20. echarts Y轴单位右对齐

热门文章

  1. 西门子PPI协议转成OPC协议
  2. 2005中文博客排名报告
  3. animator 控制移动_Unity动画机制 Animator与Animator Controller教程
  4. #4617. 逛公园
  5. tpcc压测oracle,tpcc测试数据库性能
  6. startsWith方法
  7. web前端-TypeScript学习
  8. php实现微信公众号生成淘宝客推广海报(正则匹配淘宝联盟) 1
  9. QML学习系列-Qt QML是什么?
  10. Bigint Multiplication:大数乘法(hihoCoder C++)