为什么要防抖和节流?
**函数防抖的目的:****防止函数在极短的时间内反复调用,造成资源的浪费,造成性能问题**。
栗子 1:
滚动条滚动、窗口尺寸变化、鼠标移动
如果我们需要监听这类事件,当它们发生变化时,哪怕只变化了一点点,都有可能造成成百上千次函数调用,这对网页性能的影响是极其巨大的。
- 因此,如果我们只在每次变化结束时调用一次事件方法,就可以解决性能问题了,而区别”上次变化“和” 这次”变化,就需要指定一段时延,和就像电梯关门那样。
栗子 2
搜索的场景(input 框)
以百度搜索框为例,需求是:每当输入一个文字(键盘按下事件),立即将已输入的值发送给远程服务器以请求返回对应的搜索结果,这样用户不用去点搜索按钮,可以提升用户体验。
但是
这样做同时也引发了一个性能问题:
比如我要搜索的是“JS 防抖和节流”,如果我是一个字一个字敲进 input 框去的,那么浏览器就需要请求 7 次服务器,而实际上我只需要最后一次,而之前的 6 次请求发送的是不完整的信息,就不是实际我想搜的。这样就造成了资源的浪费
也就是说:防抖是为了减少这些无意义的请求,优化性能。
函数节流的目的:有时会为页面绑定 resize 事件,或者为一个页面元素绑定拖拽事件(其核心就是绑定 mousemove),这种事件有一个特点,就是用户不必特地捣乱,他在一个正常的操作中,都有可能在一个短的时间内触发非常多次事件绑定程序。
而 DOM 操作时很消耗性能的,这个时候,如果你为这些事件绑定一些操作 DOM 节点的操作的话,那就会引发大量的计算,在用户看来,页面可能就一时间没有响应,这个页面一下子变卡了变慢了。甚至在 IE 下,如果你绑定的 resize 事件进行较多 DOM 操作,其高频率可能直接就使得浏览器崩溃
二者异同
方法相同:闭包+setTimeout
二者都是以闭包的形式处理,用**setTimeout 方法****控制事件触发频率**(将需要触发的函数作为定时器的回调函数)
目的相同:避免频繁调用函数,造成资源和性能问题
强调的都是为了避免频繁调用方法,为函数调用指定一个时间间隔
区别在于节流是在指定时间间隔内只认第一次(触发函数调用),而防抖只认最后一次
节流
概述:
只认第一次事件触发,在一段时间内无论触发多少次,都只执行第一次事件触发,并在计时结束后给出响应
逻辑:
应用场景:
输入、搜索功能
实现
1 | /** |
使用:在 onScorll 中使用节流
1 | // 使用 throttle 来包装 scorll 的回调函数,设置间隔时间为1s |
防抖
概述:
只认最后一次事件触发,在一段时间内无论触发多少次,都只执行最后一次事件触发
逻辑:
- 声明一个 debounce 函数
- 传入要防抖的函数和指定延迟(设一个默认值),然后–
应用场景:
登录、注册、支付
实现
1 | /** |
使用:在 onScorll 中使用防抖
1 | // 用debounce来包装scroll的回调 |
节流防抖一体化
为什么要一体化
用 Throttle 来优化 Debounce
- 防抖的问题是:当用户操作频繁时,debounce 将不断地销毁和重建定时器,用户迟迟得不到响应,会误以为“页面卡死”
- 为此,我们需要借助Throttle的思想,打造一个“有底线”的debounce,等你可以,但我有我的原则:delay 时间内,我可以为你重新生成定时器,但是只要 delay 时间一到,我就**必须给用户一个响应**。
逻辑
实现
1 | /** |
使用:在 onScorll 中使用加强版 throttle
1 | // 用throttle来包装scroll的回调 |
参考:
评论