这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战
函数的防抖和节流
我们自己规定频繁触发的条件[例如:我们规定300ms内,只要触发两次就是频繁]
防抖:防止“帕金森”,在频繁触发的模式下,我们只识别一次[识别第一次,也可以识别最后一次]
节流:降低触发的频率,他能识别“多次”[浏览器有自己的最快反应时间,例如:谷歌57ms IE 1017ms,
这样在我们的疯狂操作下,谷歌浏览器的频率是5ms执行一次,节流是降低这个频率,比如我们设定频率是300ms,
在疯狂触发的时候,我么能控制间隔300ms才让其执行一次]
一般点击事件以防抖为主 [但是有些需求也是节流]
键盘输入事件 或者 滚动条滚动事件 都是以节流为主
防抖
动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一定时间再触发事件。
具体方法是:在上一次事件触发之后的 time 时间内如果事件没有再次触发,那么就在 time 时间后触发,否则将触发的时间作为新的起始点
通俗理解就是,将密集的时间触发事件看作一个时间整体,整个整体只触发一次事件,密集的界定就是相邻事件触发时间小于 time,则以这个整体的最后一次事件触发为起始点
function debounce(func, time) {
let timer = null;
return () => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, time);
};
}
使用闭包的原因
原因是 timer 变量是在 debounce 函数内部初始化的时候声明的,但是之后每一次触发返回的箭头函数的时候都需要读取 timer 变量,所以要使用闭包
节流
动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发。
节流和防抖大致相同,不同点在于:
- 防抖是“随机应变”,以密集的事件触发处的末尾为下一次事件触发的计时开始处
- 节流是“铁打不动”,始终以第一次事件触发为起始点,忽略
time时间内的所有事件,第一次事件发生time事件之后触发第二次事件
在数轴上理解的相同点和区别为:
在 [2, 5] 时间内触发的所有事件都浓缩为一次事件,区别是:防抖将此次事件的发生事件定在最后一次事件触发的时间,节流将时间定在第一次事件触发的时间
function throtte(func, time) {
let activeTime = 0;
return () => {
const current = Date.now();
if (current - activeTime > time) {
func.apply(this, arguments);
activeTime = Date.now();
}
};
}
上一个代码分析
let box = document.querySelector('.box')
// debounce:函数防抖
// @params
// func [function,required]:最后要执行的函数
// wait:[number]设定的频繁触发的频率事件,默认值是300
// immediate:[boolean]设置是否在开始边界触发,默认值是false
// @return
// func执行返回结果
// update 2021/08/25 by quanquan
function debounce(func,wait,immediate){
if(typeof func!== "function") throw new TypeError('func must be required and be an function')
if(typeof wait==="boolean"){
immediate = wait;
wait = 300;
}
if(typeof wait !== "number") wait = 300;
if(typeof immediate!== "boolean") immediate = false
var timer = null;
return function proxy(){
if(timer) clearTimeout(timer);
timer = setTimeout(function(){
if(timer){
clearTimeout(timer);
timer = null;
}
func();
},wait)
}
}
// 第一次点击 0
// 设置定时器 -> 300ms
// 第二次点击 5ms
// 把之前设定的定时器干掉
// 设置一个新的 设置定时器 -> 300ms
// 第三次点击 5ms
// ......
// 一直到设定一个新的定时器,但是在300ms内没有触发第二次
// 模拟获取数据
function queryData(callback){
setTimeout(() =>{
typeof callback === "function" ? callback('OK') : null;
},1000)
}
function fn() {
console.log('OK')
}
box.onclick = debounce(fn,300,true)
// box.onclick = proxy 疯狂点击box,疯狂触发proxy,但是我们最终想执行的是fn,
// 所以需要我们在proxy中,基于一些逻辑的处理,让fn只执行一次
// let isRun = false;
// box.onclick = function(){
// if(isRun) return ;
// isRun = true
// // console.log('点我干啥!')
// queryData(result => {
// console.log(result)
// isRun = false
// })
// }
此类文章持续迭代更新中,请持续关注吧。
最后来个小广告,最近突发奇想想见一个高质量前端技术交流群,目前群里有网易、百度、字节大佬,欢迎入群,一起学习。
前端路漫漫其修远兮,吾将上下而求索,一起加油,学习前端吧
欢迎留言讨论~