防抖
事件响应(func)在一段时间(wait)后才执行,如果在这段时间内再次调用,则重新计算时间。
应用场景:
scrool事件滚动触发- 搜索框输入查询
- 表单验证
- 按钮提交事件
- 浏览器窗口缩放,resize事件等
function debounce(func, wait, immediate){
let timeOut,result; // result 防止调用函数有return
let debounced = function(){
let self = this, // 指向调用主体
args = arguments;
if(timeOut) clearTimeout(timeOut);
if(immediate){ // 立即执行
let callNow = !timeOut;
timeOut = setTimeout(()=>{ // 规定时间后可以继续执行
timeOut = null
},wait);
if(callNow) result = func.call(self,...args)
}else {
timeOut = setTimeout(()=>{
result = func.call(self,...args)
},wait)
}
return result
}
//终止执行
debounced.cancel = function(){
clearTimeout(timeOut);
timeOut = null // timeOut变量被闭包私有化,清除。
}
return debounced
}
节流
如果你持续触发事件,每个一段事件,只执行一次事件。利用定时器以及时间差。
应用场景:
window对象的resize、scroll事件- 拖拽时候的
mousemove - 射击游戏中的
mousedown、keydown事件 - 文字输入、自动完成的
keyup事件等
第一版 第一次触发,最后不会被调用触发函数(leading为true,trailing为false)用时间差方式实现
function throttle(func, wait, options = {}){
let oldTime = 0, self, args, newTime
return function (){
self = this;
args = arguments;
newTime = new Date().valueOf();//取时间戳
if(newTime - oldTime > wait){
func.call(self,...args);
oldTime = newTime
}
}
}
第二版 第一次不触发,最后会被调用触发函数(leading为false,trailing为true)用定时器方式实现
function throttle(func, wait, options = {}){
let timeOut, self, args;
return function(){
self = this;
args = arguments;
if(!timeOut){
timeOut = setTimeout(()=>{
func.call(self, ...args)
timeOut = null
},wait)
}
}
}
第三版 第一次触发,最后也调用触发函数(leading为true,trailing为true)
function throttle(func, wait, options = {}){
let timeOut, self, args, newTime, oldTime;
oldTime = 0;
return function(){
self = this;
args = arguments;
newTime = new Date().valueOf();
if(newTime - oldTime > wait){
if(timeOut){
clearTimeout(timeOut)
timeOut = null;
}
func.call(self, ...args)
oldTime = newTime
};
if(!timeOut){
timeOut = setTimeout(()=>{
oldTime = new Date().valueOf();
func.call(self, ...args)
timeOut = null
},wait)
}
}
}
第四版 实现leading、trailing控制
- leading 控制第一次是否触发
- trailing 控制最后一次是否触发
leading与trailing 不允许同时设置为false
function throttle(func, wait, options = {}){
let timeOut, self, args, newTime,oldTime;
oldTime = 0;
let later = function(){
oldTime = new Date().valueOf();
func.call(self, ...args)
timeOut = null
}
return function(){
self = this;
args = arguments;
newTime = new Date().valueOf();
if(!options.leading && oldTime == 0){
oldTime = newTime
}
if(newTime - oldTime > wait){
if(timeOut && options.trailing){
clearTimeout(timeOut)
timeOut = null;
}
func.call(self, ...args)
oldTime = newTime
};
if(!timeOut && options.trailing){
timeOut = setTimeout(later,wait)
}
}
}