性能优化:防抖与节流

面到麻木💀,害怕
防抖
防抖:反复执行,只会执行最后一次或者第一次。
实现:每次事件触发就删除原来的定时器,建立新的定时器。通过immediate选择是立即执行还是最后执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function debounce(fun, delay = 500,immediate = true) { let timer = null return function (args) { let that = this let _args = args if (timer) clearTimeout(timer); if (immediate) { if ( !timer) fun.apply(that, _args) timer = setTimeout(function(){ timer = null; }, delay) } else { timer = setTimeout(function(){ fun.call(that, _args) }, delay); } } }
|
节流
节流:一段时间内只能触发一次。
实现:用一个状态来控制执行,如果已经这段时间内已经执行过了,就不执行了。否则就执行。
定时器版
开始触发时等n秒后执行,停止触发后继续执行一次事件
1 2 3 4 5 6 7 8 9 10 11
| const throttle = (fn, wait = 300) =>{ let timeId return function(...args){ if(!timeId){ timeId = setTimeout(() =>{ fn.apply(this, ...args) timeId = null }, wait) } } }
|
时间戳版
开始触发时立即执行,停止触发后不再执行事件
1 2 3 4 5 6 7 8 9 10
| const throttle = (fn, wait = 300) =>{ let prev = 0 return function(...args){ let now = +new Date() if(now - prev > wait){ prev = now fn.apply(this, ...args) } } }
|
这里补充一下面试过程想到的写法,同时间戳版
1 2 3 4 5 6 7 8 9 10 11 12
| function throttle(func,wait) { let preTime = Date.now(); let nowTime; return function(...args) { let that = this; nowTime = Date.now(); if(nowTime - preTime >= wait) { preTime = Date.now(); func.apply(that,args); } } }
|
防抖节流合并-高级版节流
固定时间内会给用户一个响应
当 remain <= 0 时表示该执行了(保证了第一次触发事件就能立即执行和每隔 wait 时间执行一次)。
还没到时间的话就设定在 remain 时间后再触发(保证了最后一次还能再执行一次)。
在 remain 这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const throttle = (fn, wait = 300) => { let prev = 0 let timeId return function(...args){ timeId && clearTimeout(timeId) let now = +new Date() let remain = wait - (now - prev) if(remain <= 0){ fn.apply(this, args) prev = now } else{ timeId = setTimeout(fn, remain) } } }
|