节流防抖是js的一种优化手段,也是平时工作中经常用到的一种优化方式,主要作用在实时搜索,滚动屏幕,变更窗口大小,连续点击...情景,如果每次触发事件都有一个较为复杂的函数,那么浏览器的负荷太重了,严重的话会造成浏览器卡死的现象。在这一方面消耗浏览器的太多性能是没有必要的。所以就出现了我们下面要说的节流防抖了;
节流
节流是什么?
如果有一个input框,每次输入就会触发ajax请求,那么请求的太频繁了,那么我们可以给他规定一个时间段去请求一次,例如一秒请求一次。这样就大大的节省了http请求。从而对浏览器的性能也是大大的提高。
代码实现
现在html中有一个input输入框,每次按下限制每隔一秒执行;
html
js
let input = document.getElementById('input')
function throttling(func, wait) {
let prev = 0;
let choke = function () {
let now = Date.now();
let remain = wait - (now - prev);
if (remain <= 0) {
func.apply(this,arguments);
prev = now;
}
}
return choke
}
function logger() {
console.log('-----logger---',input.value)
}
document.addEventListener('input', throttling(logger, 1000))
上面代码就实现了一个简单的节流方法,但是还存在问题,就是不能输出最后录入的值(如图),很明显这不是很友好;
产品爸爸:你这个辣鸡程序员我在输入框中输入了上面的数据为啥给我搜索出下面的数据,你这不骗人吗!
程序员:好的爸爸。我改!
那么我们需要实现一个不再录入时获取最后一次的值。
let input = document.getElementById('input')
function throttling(func, wait) {
let prev = 0,
timer;
let choke = function () {
let now = Date.now();
let remain = wait - (now - prev);
if (remain <= 0) {
if(timer){
clearTimeout(timer);
timer=null;
}
func.apply(this, arguments);
prev = now;
} else if (!timer) {
timer = setTimeout(() => {
func.apply(this, arguments)
},remain)
prev = Date.now()
}
}
return choke
}
function logger() {
console.log('-----logger---', input.value)
}
document.addEventListener('input', throttling(logger, 1000))
经过上面改良后的方法我们再重新输入,就完美的实现了xx产品的需求。
学节流时遇到的问题
- 1 什么情况下会走第一个判断
let remain = wait - (now - prev)
;
我们设定的值是1000ms
now是当前的时间戳 假设为1000;
prev初始值是 0;
第一次输入的字节:肯定是负数/0 那么就会走第一个判断中,直接让logger函数执行。并且将prev设置成上一次输入的时间。
- 2 走第二个判断
第二次输入字节:连续输入时第二次的now假如是1200ms,prev是1000,那么remain是正数,然后判断没有timer就会走到第二个判断中,直接开启定时器。
- 3 为什么在第二个判断中使用remain作为时间呢?
因为这次输入是1200ms,上次输入是1000ms,remain的值就是800ms这样就符合我们传进来的1000ms的时间了,在这里不用传进来的wait而用remain是为了让程序更严谨一点。
- 4 为什么要传入arguments?
arguments在这里是一个事件对象,arguments是不用写在函数上形参的类数组(es6),所以可以直接使用apply
- 5 如果想给logger函数传参怎么办?
input.addEventListener('input', throttling(logger, 1000))(xxx)
是不行的,这样会直接执行的,那么我们就在他的外层再包一层函数就可以了
function logger(e,parmes) {
console.log('-----logger---',e, parmes)
}
input.addEventListener('input', (e)=>{
throttling(logger, 1000)(444)
})
防抖
防抖就是在规定时间连续输入时只取最后一次的值(只要输入时停顿的时间不超过规定值那么就不会执行)
这里打印台只触发了一次
代码实现
let input =document.getElementById('input');
function debounce(func,wait){
let timer;
return function(){
clearTimeout(timer);
timer=setTimeout(()=>{
func.apply(this,arguments)
},wait)
}
}
function logger(){
console.log('--logger--',input.value)
}
input.addEventListener('input',debounce(logger,1000))
防抖的代码就简单多了,上面的代码是只要停顿不超过1s,那么上次赋值的timer直接会被清空
应用场景
节流
1.鼠标不断点击触发,mousedown(单位时间内只触发一次)
2.屏幕滚动的触底事件
防抖
1.实时搜索框 一直输入在特定的时间内一直搜索,比如百度的搜索框会一直获取联想词
2.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次