深入理解节流和防抖
节流和防抖,是在前端面试的时候,有很大概率会被提到的问题,我曾经就遇到过,虽然我了解过这两个概念,在工作中其实也用到过,但是被面试官一问,还是懵了,没办法,厚着脸皮让人家给举个适用场景,我说了下解决方案。
之前也的确没有写到过节流和防抖的博文,虽然网上有很多介绍他俩的文章,但我还是觉得自己总结写篇文章,会理解的更好记忆的也会更深刻一些。下面就正式开始吧~
其实节流和防抖,可能单独说名词,有的朋友会恍惚一下,感觉我不清楚啊,其实在工作中,你是有用到过的,想要理解,最好先知道他俩的共同点,区别以及适用场景。
共同点:都是用于处理高频事件的,一个事件被高频率触发,一个是比较消耗浏览器性能,再一个就是它们触发的事件,如果是一个相对复杂的事情,可能第一次触发还没处理完,第二次又被触发了,显然这不是正常的情景。
区别:
字面上理解,防抖,就像我们拍照,抖动的时候拍的不清楚,会重影,什么时候不抖了,什么时候拍照,直译到js里就是,对于高频触发的时间,我们需要定义一个时间,在这个时间以内事件触发,那么我们不去调用方法,什么时候过了这个时间,事件没有被再次触发,那就可以执行方法了,简而言之,防抖只会执行一次;
而节流呢,你可以把它想象成一个水龙头,而且是拧紧一点的那种,但是还没有完全拧紧,这个水龙头会以比较缓慢的时间一滴一滴的去滴水,这其实就是节流,放到项目里,就是控制这个高频的事件发生的频率,比如每隔1秒执行一次。
结合使用场景再来理解一下。
防抖适用场景:
用户登录、发送短信验证码、调整浏览器窗口大小等。
我们具体来说一下,用户登录、获取短信验证码,这种情况一般都是按钮触发http请求,为防止用户频繁点击按钮,登录的情况下,一般在请求完成前,会先禁用按钮,等请求完成后再解禁,比如:
userLogin: function(userLoginData) {
$.ajax({
url: ajaxUrlNew + '?requestType=UserLogin',
type: 'post',
dataType: 'json',
async: false,
data: userLoginData,
beforeSend: function() {
//禁用按钮
$('#loginbtn').attr("disabled", true);
$('#loginbtn').text("登录中,请稍后");
},
success: function(data) {
//data.Status的值为true 如果用户信息为空 提示登录失败 如果值不为空 则进行跳转
if (data.Status) {
//登录成功 页面跳转等
window.location.href = 'index.html';
} else {
//data.Status的值为false 判断是用户名还是密码错误 并给出对应提示 登录失败
layer.msg(data.Msg, {
icon: 5
});
$('#txtPhoneNum').val('');
$('#txtPW').val('');
return false;
};
},
complete: function() {
//按钮解禁
$('#loginbtn').removeAttr("disabled");
$('#loginbtn').text("登录");
},
error: function(err) {
console.log(err);
}
});
}
而获取短信验证码的需求,一般情况是请求前设置一个120s或者60s的倒计时,等倒计时结束后,才会允许用户再次请求,示例代码如下:
getRandomPassword: function() {
var getrandomcodeBtn = $("#getrandomcode");
getrandomcodeBtn.click(function() {
$.ajax({
url: ajaxUrlNew + '?requestType=GetPasswordService',
type: 'post',
dataType: 'json',
data: {
'phonenumber': window.sessionStorage.phoneNum
},
success: function(data) {
if (data.Status) {
layer.alert('随机验证码已发送,请注意查收', {
skin: 'mybtn-class'
});
setTime = setInterval(function() {
if (time <= 0) {
clearInterval(setTime);
$("#getrandomcode").removeAttr("disabled");
$("#getrandomcode").val("获取验证码");
return;
}
time--;
$("#getrandomcode").val(time + "s后重新获取");
$("#getrandomcode").attr("disabled", "true");
}, 1000);
} else {
layer.alert(data.Msg, {
skin: 'mybtn-class'
});
}
},
error: function(err) {
console.log(err);
}
});
});
},
最后再举一个调整浏览器大小的例子:
function debounce(operate, delay) {
let time = null;
let timer = null;
let newTime = null;
function task() {
newTime = +new Date()
if(newTime - time < delay){
timer = setTimeout(task, delay)
}else {
operate()
timer = null
}
time = newTime
}
return function () {
// 更新时间戳
time = +new Date()
if(!timer){
timer = setTimeout(task, delay)
}
}
}
//打印可视区域宽度
function printWidth() {
console.log(window.document.body.clientWidth)
}
//监听resize事件
window.addEventListener('resize', debounce(printWidth, 500), false)
节流使用场景:
scroll事件、input输入实时搜索事件等。
scroll事件,比如我们有这么一个需求,当滚动高度大于多少时,我们载入某个动画,如果我们不做节流,那scroll事件会频繁触发,但是如果们限制200ms才触发一次,然后再去对比是否符合要求呢?是不是就好很多?
function throttle(func, wait, mustRun) {
var timeout,
startTime = new Date();
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;
}else{
timeout = setTimeout(func, wait);
}
};
};
function realFunc(){
console.log("Success");
}
window.addEventListener('scroll',throttle(realFunc,500,1000));
这里借用了一个别人的例子,谢谢~
对于input输入实时搜索事件,怎么去做节流处理呢,其实也是一样的,我们可以监听keyup事件,不过是每隔一段时间取监听一下。
节流和防抖就简单说了一下下,有什么不到位的地方,希望看到的朋友指出来,我积极整改~拜拜~
- 点赞
- 收藏
- 关注作者
评论(0)