前言
我们知道, 在我们做项目的时候有时候会用到防抖和节流,比如们在提交表单的时候,或者点击某个按钮获取数据的时候,为了防止点击的频率过快导致重复的请求,我们会使用防抖来处理,在比如有时候在使用搜索的时候频繁改变输入内容,我们想要隔一段时间内获取一次,就要使用节流
共用代码:
function subnum() { console.log(1); } var btn = document.querySelector(".btn"); console.log(btn); btn.addEventListener("click", debounce(subnum, 1000), false)
防抖函数的实现 🐤🐤
我们首先实现一个简易版的
//封装防抖函数的实现 function debounce(fn, time) { var t = null; // 这里其实利用了闭包的原理,可以保存变量 return function () { var _this = this; var args = arguments; // 清除上次的定时器 if (t) { clearTimeout(t); } t = setTimeout(function () { fn.apply(_this, args); }, time); }; }
- 首先我们先讲解一下防抖函数的核心原理:在点击的事件触发之后,首先清除上次的定时器,如果是第一次点击那就进行下一步,设置定时器,此时达到了延时的目的,如果在定时器期间有触发了点击事件,那么此时就会清除上次的定时器(此时定时器中的回调函数没有执行)直到不在重复点击的时候才会最终触发定时器中的回调函数,并且触发fn函数。这就达到了防抖的目的。
- 但是目前这个防抖函数还是有就局限性,就是当第一次点击的时候,还是会延时触发,这样就会在某些场景下不满足需求,比如我们想要在第一次点击的时候立即获取,但是如果重复点击的话还是执行最后一次点击,这种情况就不满足。因此我们要对这个防抖函数进行改造,使其功能更加强大
完善防抖函数✌️✌️
function debounce(fn, time, triggleNow) { var t = null; // 这里其实利用了闭包的原理,可以保存变量 return function () { var _this = this; var args = arguments; // 清除上次的定时器 if (t) { clearTimeout(t); } // 如果是true表明第一次点击时立即执行函数 if (triggleNow) { var exec = !t; if (exec) { fn.apply(_this, args); } t = setTimeout(function () { t = null; }, time); } else { t = setTimeout(function () { fn.apply(_this, args); }, time); } }; }
- 首先这次显而易见的是我们函数设计上多设计了一个形参,这个形参的目的就是控制是否要再第一次点击的时候立即执行函数
- 这个功能的实现原理:首先如果triggleNow为true时,会进入下面的分支判断中,此时由于时第一次点击t的值为null,那么!t即为true,即exec为true,就会进入下面的判断中,执行fn函数,然后在执行定时器中的回调函数(前提是没有重复点击),否则此时定时器中的回调还是不会执行,当定时器中的回调函数执行之后t被赋值为null。这样就实现了第一次点击的时候立即执行
使用场景:
比如我们此时要进行ajax请求,那么我们就需要进行防抖处理,并且在第一次点击的时候立即进行数据的请求
可以发现我们在点击的时候只有第一次会触发,多次点击也只会触发一次
当然有时候我们是需要第一次也延时获取的,比如一下场景:当我们在搜索框输入内容的时候,我们不想在第一次输入内容的时候就请求数据,这个时候我们就需要将triggleNow设置为fasle。然后当停止输入一段时间之后才会请求数据
节流函数的实现🎈🎈
节流函数和防抖函数类似,但是略有不同,防抖函数是在规定的时间内,不管你点击多少下只会触发最后一次,节流则是在一段时间内执行一次。
直接贴上代码
// 节流函数 function throttle(fn, time) { var begin = new Date().getTime(); console.log(begin); return function () { clearTimeout(t); var _this = this; var args = arguments; var cur = new Date().getTime(); if (cur - begin > time) { fn.apply(_this, args); } begin = cur; }; }
在网上查阅资料,发现很多人的节流函数是这么写的。这样做确实也可以,但是如果我频繁的点击,并且在设置的一段时间内,那么如果我点击的足够快造成的结果就是这个函数一次也不会调用,我认为这有些不合适。于是我进行了一些改造
function throttle(fn, time) { var t = null; var begin = new Date().getTime(); console.log(begin); return function () { clearTimeout(t); var _this = this; var args = arguments; var cur = new Date().getTime(); if (cur - begin > time) { fn.apply(_this, args); } else { t = setTimeout(function () { fn.apply(_this, args); }, time); } begin = cur; }; }
这样改进后的如果在时间间隔内调用,那么会执行函数,如果频繁的点击,那么也会执行一次函数,这样就实现的功能比较全面
那么我就说一下实现的思路:
- 首先创建一个t变量为null,然后在页面渲染的时候就会调用throttle函数,创建begin变量,然后在点击事件触发的时候,先清除之前的定时器,然后获取点击的时候的当前时间戳,然后用当前的时间戳去减去之间的时间戳如果时间大于time那么此时就可以执行函数
- 否则如果时间间隔小于time的时候,当不在点击的时候就会执行一次,注意让最后执行完成之后,会将cur赋值给begin,作为下次的开始的时间戳。
使用场景:其实节流函数和防抖函数的使用场景会有冲突,具体的使用情况要看业务的需求,节流函数也可以使用在比如ajax的请求上面,或者在拖动滚动条需要监听滚动条的时候,就也可以使用节流函数
总结 🤠🤠
防抖函数和节流函数我们能经常遇到,无论是在面试过程中,还是在实际的项目开发中,这就要求我们必须掌握这部分知识,并且这两个函数输入功能型函数,实现封装之后,复用性比较高。因此掌握还是非常有必要的