防抖和节流的理解,及其应用场景
01****概 念
**目的:**当多次执行某一动作,进行函数调用次数的限制,节省资源
**防抖:**在事件触发n秒后执行函数,如果在n秒内再次出发,重新计时
**节流:**当多次执行某一动作,每隔一段时间,只执行一次函数。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。
比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
( 简要回答 )
**防抖:**防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零
**节流:**控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit。代码实现重在开锁关锁
02
应用场景
函数防抖的应用场景
连续的事件,只需触发一次回调的场景有:
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测(change、input、blur、keyup等事件触发,每次键入都会触发)
- 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
- 鼠标的mousemove、mouseover
- 导航条上,用户不停的在导航区域滑动相当于
函数节流的应用场景
间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听,window.onscroll和滑到底部自动加载更多
- 谷歌搜索框,搜索联想功能
- 高频点击提交,表单重复提交
03
防抖的实现
防抖函数(普通)
1var timer; //全局的timer,只有一个
2function debounce(fn,delay){
3 if(timer){
4 clearTimeout(timer) //保证只开启一个定时器
5 }
6 timer = setTimeout(function(){
7 fn(); //延迟delay,执行函数
8 },delay)
9}
10window.onscroll = function(){
11 debounce(test,1000)
12}
13function test(){
14 console.log('滚动停')
15}
需要将timer封装到debounce中,如果调用的fn有参数需要处理
1function debounce(fn,delay){
2 let timer;
3 return function(){
4 let _this = this; //为了改写参数 保存this 应用apply
5 let _args = arguments; //保存testDebounceFn的入参
6 if(timer){
7 clearTimeout(timer);
8 }
9 timer = setTimeout(function(){
10 //apply传参正好和arguments匹配
11 fn.apply(_this,_args)
12 },delay)
13 }
14}
15let testDebounceFn = debounce(test,1000);
16function test(a){
17 console.log('滚动停 '+a)
18}
19window.onscroll = function(){
20 testDebounceFn('aaaa')
21}
04
节流的实现
节流(2种方式setTimeout 或者 new Date()) 防抖比节流严格,防抖在一定时间操作后只执行一次。节流在一定时间操作,可每隔n秒执行一次
setTimeout方式
1function throttle(fn,delay){
2 let timer;
3 return function(){
4 let _args = arguments;
5 let _this = this;
6 if(timer){//如果有定时器,退出
7 return
8 }
9 timer = setTimeout(function(){
10 fn.apply(_this,_args);//定时器结束执行函数
11 timer = null;//清除定时器,可以再次进入
12 },delay)
13 }
14}
15let testThrottleFn = throttle(test,3000);
16function test(a){
17 console.log('打印 '+a)
18}
19window.onscroll = function(){
20 testThrottleFn('bbbb')
21}
new Date方式
1function throttle(fn,delay){
2 let previous = 0;
3 return function(){
4 let _this = this;
5 let _argus = arguments;
6 let now = new Date();
7 //不同时间取值的new Date()是可以相减的
8 if(now-previous>delay){
9 fn.apply(_this,_argus);
10 previous = now;
11 }
12 }
13}
14let testThrottleFn = throttle(test,2000);
15function test(b){
16 console.log('出现 '+b)
17}
18window.onscroll = function(){
19 testThrottleFn('8888')
20}
个人笔记记录 2021 ~ 2025