去抖
函数调用 n 秒后才会执行,如果函数在 n 秒内被调用的话则函数不执行,重新计算执行时间,这里的原理是利用了一个闭包,每当有事件被监听就清除闭包中timer,重新赋值
// debouncefunctiondebounce(method,delay){vartimer=null;returnfunction(){varcontext=this,args=arguments;clearTimeout(timer);timer=setTimeout(function(){method.apply(context,args);},delay);}}比如resize()一瞬间调用了很多次,只会延迟触发最后一次调用,再比如用户在短时间触发了很多次输入动作oninput,就会延迟只触发最后一次,我们可以把它用在scroll、resize和input这些事件监听上,减少不必要的性能开销,还可以在下列事件下做去抖处理
window对象的resize、scroll事件- 拖拽时的
mousemove事件 - 射击游戏中的
mousedown、keydown事件 - 文字输入、自动完成的
keyup事件
functionresizeHandler(){console.log(this);}window.onresize=debounce(resizeHandler,500);functioninputHandler(){console.log(this);}document.getElementById("input").oninput=debounce(inputHandler,500);更进一步,我们不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行
这里增加一个 immediate 参数来设置是否要立即执行
functiondebounce(func,delay,immediate){vartimer=null;returnfunction(){varcontext=this;varargs=arguments;if(timer)clearTimeout(timer);if(immediate){//根据距离上次触发操作的时间是否到达delay来决定是否要现在执行函数vardoNow=!timer;//每一次都重新设置timer,就是要保证每一次执行的至少delay秒后才可以执行timer=setTimeout(function(){timer=null;},delay);//立即执行if(doNow){func.apply(context,args);}}else{timer=setTimeout(function(){func.apply(context,args);},delay);}}}节流
函数预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期
// throttlefunctionthrottle(method,duration){varbegin=newDate();returnfunction(){varcontext=this,args=arguments,current=newDate();if(current-begin>=duration){method.apply(context,args);begin=current;}}}- 函数的节流和函数的去抖都是通过减少实际逻辑处理过程的执行来提高事件处理函数运行性能的手段,并没有实质上减少事件的触发次数
| - | 作用 |
|---|
| 防抖动 | 将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。 |
| 节流 | 使得一定时间内只触发一次函数。 它和防抖动最大的区别就是,节流函数不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而防抖动只是在最后一次事件后才触发一次函数。 |
Vscode 的写法
vscode/extensions/git/src/decorators.ts
import{done}from'./util';functiondecorate(decorator: (fn: Function,key: string)=>Function): Function{return(_target: any,key: string,descriptor: any)=>{letfnKey: string|null=null;letfn: Function|null=null;if(typeofdescriptor.value==='function'){fnKey='value';fn=descriptor.value;}elseif(typeofdescriptor.get==='function'){fnKey='get';fn=descriptor.get;}if(!fn||!fnKey){thrownewError('not supported');}descriptor[fnKey]=decorator(fn,key);};}function_memoize(fn: Function,key: string): Function{constmemoizeKey=`$memoize$${key}`;returnfunction(this: any, ...args: any[]){if(!this.hasOwnProperty(memoizeKey)){Object.defineProperty(this,memoizeKey,{configurable: false,enumerable: false,writable: false,value: fn.apply(this,args)});}returnthis[memoizeKey];};}exportconstmemoize=decorate(_memoize);function_throttle<T>(fn: Function,key: string): Function{constcurrentKey=`$throttle$current$${key}`;constnextKey=`$throttle$next$${key}`;consttrigger=function(this: any, ...args: any[]){if(this[nextKey]){returnthis[nextKey];}if(this[currentKey]){this[nextKey]=done(this[currentKey]).then(()=>{this[nextKey]=undefined;returntrigger.apply(this,args);});returnthis[nextKey];}this[currentKey]=fn.apply(this,args)asPromise<T>;constclear=()=>this[currentKey]=undefined;done(this[currentKey]).then(clear,clear);returnthis[currentKey];};returntrigger;}exportconstthrottle=decorate(_throttle);function_sequentialize(fn: Function,key: string): Function{constcurrentKey=`__$sequence$${key}`;returnfunction(this: any, ...args: any[]){constcurrentPromise=this[currentKey]asPromise<any>||Promise.resolve(null);construn=async()=>awaitfn.apply(this,args);this[currentKey]=currentPromise.then(run,run);returnthis[currentKey];};}exportconstsequentialize=decorate(_sequentialize);exportfunctiondebounce(delay: number): Function{returndecorate((fn,key)=>{consttimerKey=`$debounce$${key}`;returnfunction(this: any, ...args: any[]){clearTimeout(this[timerKey]);this[timerKey]=setTimeout(()=>fn.apply(this,args),delay);};});}参考文档
去抖
函数调用 n 秒后才会执行,如果函数在 n 秒内被调用的话则函数不执行,重新计算执行时间,这里的原理是利用了一个闭包,每当有事件被监听就清除闭包中
timer,重新赋值比如
resize()一瞬间调用了很多次,只会延迟触发最后一次调用,再比如用户在短时间触发了很多次输入动作oninput,就会延迟只触发最后一次,我们可以把它用在scroll、resize和input这些事件监听上,减少不必要的性能开销,还可以在下列事件下做去抖处理window对象的resize、scroll事件mousemove事件mousedown、keydown事件keyup事件更进一步,我们不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行
这里增加一个 immediate 参数来设置是否要立即执行
节流
函数预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期
Vscode 的写法
vscode/extensions/git/src/decorators.ts
参考文档