debounce:持续触发某一个事件的时候 比如持续触发scroll的时候 函数是不执行的,当触发结束后在settimeout delay后才执行函数; 这样就避免了不断地触发
/**
Parma:
func:触发事件需要执行的函数;
delay:延迟时间;
immediate:是否在尾部执行(注:此参数在delay很小的时候看不出效果,需要把 delay设置很大才可以看出效果,此参数可以省略)
**/
// immediate为true的时候 代表立即执行 即距离上一次waite之后 下次滚动开始之前 // immediate为false的时候 代表停顿waite后执行 // true鼠标动的时候执行 false鼠标动过之后又不动的时候执行 function debounce(func,wait,immediate){ var timeout; immediate || (immediate = true);//设置默认值 wait||(wait =20); return function(){ var context = this,args = arguments; var later = function(){ timeout = null; if(!immediate) func.apply(context,args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later,wait); if(callNow) func.apply(context,args) } } function checkSlide(e){ console.log(window.scrollY); } window.addEventListener('scroll',debounce(checkSlide));
throttle:每间隔一段时间内执行事件与debounce不同的是 无论事件是否持续 都是间隔一段时间立即执行的而debounce是等待持续事件停顿的间隔时间执行的
/** *
频率控制 返回函数连续调用时,action 执行频率限定为 次 / delay
* @param delay {number} 延迟时间,单位毫秒
* @param action {function} 请求关联函数,实际应用需要调用的函数
* @param options? {leading:true,trailing:false} 第一次是否执行,默认为true,表示第一次会执行,传入{leading:false}则禁用第一次执行options.trailing:最后一次是否执行,默认为true,表示最后一次会执行,传入{trailing: false}表示最后一次不执行所谓第一次是否执行,是刚开始触发事件时,要不要先触发事件,如果要,则previous=0,remaining 为负值,则立即调用了函数所谓最后一次是否执行,是事件结束后,最后一次触发了此方法,如果要执行,则设置定时器,即事件结束以后还要在执行一次。remianing > wait 表示客户端时间被修改过。
* @return {function} 返回客户调用函数 *
/
function throttle(func, wait, options) { var context, args, result; var timeout = null; options ||(options ={leading:true,trailing:false});//默认参数 wait || (wait =1000); // 定时器 var previous = 0; // 上次触发的时间 // if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : new Date(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = new Date(); // 第一次是否执行 if (!previous && options.leading === false) previous = now; console.log(previous); // 这里引入了一个remaining的概念:还剩多长时间执行事件 var remaining = wait - (now - previous); console.log(remaining); console.log(now - previous); context = this; args = arguments; // remaining <= 0 考虑到事件停止后重新触发或者 // 正好相差wait的时候,这些情况下,会立即触发事件 // remaining > wait 没有考虑到相应场景 // 因为now-previous永远都是正值,且不为0,那么 // remaining就会一直比wait小,没有大于wait的情况 // 估计是保险起见吧,这种情况也是立即执行 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; // 是否跟踪 } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } };};