这是我参与更文挑战的第2天,活动详情查看: 更文挑战
防抖(debounce)
原理:在被触发n秒之后在执行回调,如果在这n秒内又被触发,则重新计时
应用场景:
-
按钮提交场景:防止多次提交按钮,只执行最后一次
-
搜索框联想场景:防止联想发送请求,只发送最后一次输入
解决方案:
简易版
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
- 如果在200ms内没有再次触发滚动事件,那么就执行函数
- 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
function debounce(func,wait){
let timeout;
return function(){
const context = this;
const args = arguments;
clearTimeOut(timeout);
timeout = setTimeout(() => {
func.apply(context,args);
}, wait);
}
}
复制代码
立即执行版
有时候希望立即执行,然后等到停止触发数秒后,才可以重新执行
function debounce(func,wait,immediate){
let timeout;
return function(){
const context = this;
const args = arguments;
// 有触发重新计时
if(timeout) ClearTimeout(timeout);
if(immediate){
const callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait);
// timeout = null 时 执行函数
if(callNow) func.apply(context.args);
}else{
timeout = setTimeout(() => {
func.apply(context,args);
}, wait)
}
}
}
复制代码
节流(throttle)
如果用户咋wait时间内不停的触发事件,那么就可能一直不能执行,如果需要一段时间内生效一次,就需要用到节流。
原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
适用场景:
-
拖拽场景:固定时间内只执行一次,防止高频次触发位置变动。
-
缩放场景: 监控浏览器resize
解决方案:
使用时间戳
当触发事件发生的时候,我们取出当前时间戳,然后减去之前的时间戳(最开始设值为0),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前时间戳,如果小于就跳过
function throttle(fnc,delay){
let context, args;
let previous = new Date();
return function(){
let now = new Date();
context = this;
args = arguments;
if(now - previous > delay){
func.apply(context,args);
previous = now;
}
}
}
复制代码
使用定时器
当触发事件的时候,我们设置一个定时器,在触发事件的时候如果定时器存在,就不执行,直到定时器执行,然后清空执行函数,清空定时器,在设置下一个定时器
function throttle(fnc,delay){
let timeout;
return function(){
let context = this;
let args = arguments;
if(timeout){
timeout = setTimeout(()=>{
timeout = null;
func.apply(context,args);
},delay);
}
}
}
复制代码
区别:节流不管事件触发多频繁保证在一定时间内一定会执行一次桉树,当都是自在最后一次时间后才会执行一次函数。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END