通常,在高频触发的场景下需要防抖和节流,例如:用户疯狂点击按钮、滚动事件、输入模糊匹配等。
防抖思路:也就是说,在某次高频触发下,我们只识别一次(可以控制识别第一次还是最后一次)。假设我们规定500ms内触发多次算高频触发,那么,在500ms内,我们只是别一次。
function debounce(fn, wait, immediate) {//wait:触发间隔时间,immediate为true在开始触发,false在结束时触发
//判断参数是否合法
if (typeof (fn) !== 'function') throw new TypeError(`${fn} must be an function`);
if (typeof (wait) === undefined) wait = 500;
if (typeof (wait) === 'boolean') {
immediate = wait;
wait = 500;
}
if (typeof (immediate) !== 'boolean') immediate = false;
//设置定时器返回标识
let timer = null;
//在proxy中根据频率管控handle的执行次数
return function proxy(...args) {//传入事件对象
let self = this,
now = immediate && !timer;
//以最后一次点击为准 触发函数
clearTimeout(timer);
timer = setTimeout(function () {
timer = null;
!immediate ? fn.call(self, ...args) : null;//将this和事件对象传给handle
}, wait);
//第一次触发就立即执行
now ? fn.call(self,...args) : null;
}
}
function handle(ev) {
//写自己的业务逻辑
console.log(this, ev);
}
submit.addEventListener('click', debounce(handle, 1000, true));
节流思路:在某次高频触发下,我们不只识别一次,按照我们设定的间隔时间,每达到这个频率都会触发一次。假设我们规定频率是500ms,我们操作了10min,触发的次数 =(10* 60 *1000)/500。
function throttle(fn, wait){
if (typeof (fn) !== 'function') throw new TypeError(`${fn} must be an function`);
if (typeof (wait) === undefined) wait = 500;
let timer = null,
previous = 0;//记录上一次操作时间
return function proxy(...args){
let self = this,
now = new Date(),//当前触发操作的时间
remaining = wait - (now - previous);
if(remaining <= 0){
//两次间隔超过wait了,直接执行即可
clearTimeout(timer);
timer = null;
previous = now;
fn.call(self,...args);
}else if(!timer){
//两次触发的间隔时间没有超过wait,则设置定时器,让其等待remaining这么久之后执行一次,前提是没有设置定时器
timer = setTimeout(function(){
clearTimeout(timer);
timer = null;
fn.call(self,...args);
},remaining);
}
}
}
function demo(ev){
console.log('ok');
}
window.onscroll = throttle(demo,500);