防抖节流原理、区别以及应用,请用js实现。
防抖
原理:在时间被触发n秒之后再执行回调,如果在这n秒内又被触发,则重新计时
适用场景:
- 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
- 搜索框联想场景:防止联想发送请求,只发送最后一次输入
//简易版实现
function debounce(func,wait){
let timeout;
return function(){
const context=this;
const args=arguments;
clearTimeout(timeout);
timeout=setTimeout(() => {
func.apply(context,args);
}, wait);
}
}
//立即执行版实现:有时候希望立刻执行函数,然后等到停止触发n秒后,才可以重新执行。
function debound1(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);
if(callNow) func.apply(context,args);
}else{
timeout=setTimeout(() => {
func.apply(context,args);
}, wait);
}
}
}
//返回值版实现
//func函数可能会有返回值,所以需要返回函数结果,但是当immediate为false的时候,因为使用了setTimeout,我们将func.apply(context,args)的返回值赋给变量,最后在return的时候,值将会一直是undefined,所以只在immediate为true的时候返回函数的执行结果
function debounce2(func,wait,immediate){
let timeout,result;
return function(){
const context=this;
const args=arguments;
if(timeout) clearTimeout(timeout);
if(immediate){
const callNow=!timeout;
timeout=setTimeout(() => {
timeout=null;
}, wait)
if (callNow) result=func.apply(context,args);
}else{
timeout=setTimeout(() => {
func.apply(context,args);
}, wait);
}
return result;
}
}
节流
节流的意思是,连续多次事件触发时, 会间隔触发
原理: 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效
适用场景:
- 拖拽场景:固定时间内只执行一次,防止高频次触发位置变动
- 缩放场景:监控浏览器 resize
//使用时间戳实现:使用时间戳,当触发事件发生的时候,我们取出当前的时间戳,然后减去之前的时间戳(最开始设值为0),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前时间戳,如果小于,就不执行
function throttle(func,wait){
let context,args;
let previous=0;
return function(){
let now=+new Date();
context=this;
args=arguments;
if(now-previous > wait){
func.apply(context,args);
previous=now
}
}
}
//使用定时器实现:当触发事件的时候,我们设置一个定时器,在触发事件的时候,如果定时器存在,就不执行,知道定时器执行,然后执行函数,清空定时器,这样就可以设置下定时器
function throttle1(func,wait){
let timeout;
return function(){
const context=this;
const args=arguments;
if(!timeout){
timeout=setTimeout(() => {
timeout=null;
func.apply(context,args);
}, wait);
}
}
}
//区别:节流不管事件触发多频繁保证在一定时间内一定会执行一次函数。防抖是只在最后一次事件触发后才会执行一次函数
// flag版本
const throttle2=(func,wait)=>{
let flag=true;
return function(...args){
if(!flag) return;
flag=flase;
setTimeout(() => {
func.apply(this,args)
flag=true;
}, wait);
}
}