前言
个人对节流木得啥感觉,所以想对节流函数进行复盘,总结一下。
正文
我们先来看看什么是节流?为什么要节流?有啥作用?具体咋写?
什么是节流?
在事件被触发后,在规定时间内无论在怎么触发只会调用一次函数,直到时间结束
个人理解就是游戏人物的霸体,霸体期间我们怎么打他,他都不会倒下,只能等时间结束霸体效果消失
复制代码
为什么要节流?有啥作用?
优化项目的性能,让项目运行的更快更好。
减少一些时间的频繁调用,例如scroll(懒加载要记录滚动条的位置)、mousemove(鼠标移动)等等
还有一个重要作用就是面试可能会问,我们必须知道。
复制代码
具体咋写?
定时器版
第一个参数是我们要执行的函数
第二个就是时间
function throttle(func,delay){
let timer = null
retrun function(...args){
// let args=arguments 也可以写成这种或...args也是代表我们传过来的实参
if(!timer){
timer=setTimeOut(()=>{
func.apply(this,args)
timer=null
},dealy)
}
// 当我们第一次触发事件,定时器不存在时就执行函数,当我们再次点击时,因为定时器存在,
// 所以无法再进入函数调用(无论事件如何执行),那么只能等定时器事件结束,
// 我们让timer=null,回到第一次的状态,就又重新开始新的一轮
}
}
这种功能性的函数,其实会用到很多地方,我们可以额外将其封装成一个js文件,
通过export function将其导出,再到具体使用文件里导入然后调用函数
复制代码
时间戳版
function throttle(func,delay){
let start=0
//let start=+new Date() 不可以这样写,会导致无法第一次就执行函数
return function(...args){
let now=+new Date() //通过+号可以转化成时间戳
if(now-start>delay){
func.apply(this,args)
start=now
}
}
//第一次会立即触发事件调用函数,通过判断前后触发事件的时间间隔是否大于设置的等待时间
//大于就证明已经过了规定时间,可以再次调用函数,否则反之
}
复制代码
时间戳版和定时器版区别
二者区别在于时间戳版会立即执行,好像也是存在的原因(没去了解),而定时器版是最后一次会立即执行。
但其实定时器版也可以第一次立即执行。其实只要稍作修改即可实现。
function throttle(func, delay) {
let timer = null
return function (...args) {
if (!timer) {
func.apply(this, args)//先执行函数
timer = setTimeout(() => {
timer = null;
}, delay)
}
}
}
复制代码
咋用呢?
这里结合小案例来说,以下是定时器版
没有使用节流throttle函数的情况
<div id="box"></div>
let box = document.getElementById('box')
let count = 1;
function doSomething() {
box.innerHTML = count++;
console.log('1')
};
box.onmousemove = doSomething
当我们讲鼠标在box里一直移动,他的数字会疯狂增加,会一直打印1
复制代码
效果图
使用节流throttle函数的情况
let box = document.getElementById('box')
let count = 1;
function doSomething() {
box.innerHTML = count++;
console.log('1')
};
// box.onmousemove = doSomething
box.onmousemove = throttle(doSomething, 2000);
复制代码
结果如下,打印的次数减少了,建议上机体验(在外面写的博客,没工具啊,不然就换成gif了)
额外
听说如果面试官比较BT的话,会让你写第一次也执行,中间还是节流,最后一次也要执行。这种时候不能说不会,而是我们无敌装B高光时刻就到了,将定时器和时间戳合并,俗称节流合体双修版。嘿嘿嘿嘿!
节流合体双修版
function throttle(func, delay) {
let start=0
let timer=null
return function (...args) {
let now = +new Date();
if (now - start < delay) {
if (timer) clearTimeout(timer)
// timer && clearTimeout(timer)//两种都行
// && 先算 && 左侧,若左侧为 false 那么右侧就不运算了。
timer = setTimeout(() => {
start = now;
func.apply(this, args);
}, delay);
} else {
start = now;
func.apply(this, args);
}
}
}
复制代码
总结
节流函数是指在一定时间范围内减少事件的触发频率
时间戳版和定时器版的区别在于时间戳版会立即执行,而定时器版是最后一次会立即执行,但是定时器也可以第一次执行
结合应用场景
1.搜索框联想,用户在输入值的时候,个人认为用函数节流也可以来减少请求数据的次数,不过更多用的是防抖。
2.在页面的加载场景,用户在滚动页面时,可以每隔一段时间发一次 Ajax 请求
3.等等等等。。。。。。
如果你有兴趣可以再去看看我写的debounce防抖