
前言
-
遇見的場(chǎng)景
最近有頻繁遇見的一個(gè)場(chǎng)景:在做搜索(包括數(shù)據(jù)量大做模糊搜索,后端實(shí)現(xiàn))時(shí),會(huì)遇見這種情況,在input標(biāo)簽上綁定@input 函數(shù)(請(qǐng)求函數(shù)),由于@input監(jiān)控變化時(shí),發(fā)請(qǐng)求非常高頻,以至于當(dāng)某一次請(qǐng)求回來的數(shù)據(jù)量非常大時(shí),在這次請(qǐng)求之后的返回?cái)?shù)據(jù)量小,所以先請(qǐng)求的數(shù)據(jù)量大的最后返回并展示在頁面上,導(dǎo)致用戶看起來頁面查詢出來的結(jié)果不正確;我們的目的是為了在搜索時(shí)做到結(jié)果實(shí)時(shí)顯示,但是由于@input的監(jiān) 控,在輸入搜索關(guān)鍵字的時(shí)候,發(fā)送多次http異步請(qǐng)求,這樣頻繁地請(qǐng)求會(huì)導(dǎo)致流量損耗與性能下降。
類似的常見場(chǎng)景
由于事件頻繁被觸發(fā),因而頻繁執(zhí)行DOM操作、資源加載等重行為,導(dǎo)致UI停頓甚至瀏覽器崩潰的常見場(chǎng)景:
1、window對(duì)象的resize、scroll事件;
2、 拖拽時(shí)的mousemove事件;
3、文字輸入、自動(dòng)完成的keyup事件;
為了能使這些場(chǎng)景得到優(yōu)化,就需要用到函數(shù)節(jié)流和函數(shù)防抖;
函數(shù)防抖(debounce)
概念:
當(dāng)調(diào)用動(dòng)作過n毫秒后,才會(huì)執(zhí)行該動(dòng)作,若在這n毫秒內(nèi)又調(diào)用此動(dòng)作則將重新計(jì)算執(zhí)行時(shí)間;函數(shù)實(shí)現(xiàn):
function _debounce(fn,wait){
var timer = null;
return function(){
clearTimeout(timer)
timer = setTimeout(()=>{
fn()
},wait)
}
}
function fn(){
console.log(1)
}
window.onscroll = _debounce(fn,500)
函數(shù)節(jié)流(throttle)
概念:
預(yù)先設(shè)定一個(gè)執(zhí)行周期,當(dāng)調(diào)用動(dòng)作的時(shí)刻大于等于執(zhí)行周期則執(zhí)行該動(dòng)作,然后進(jìn)入下一個(gè)新周期;函數(shù)實(shí)現(xiàn):
以頁面的滾動(dòng)事件為例,如果頁面很長(zhǎng),我們一直在滾動(dòng)頁面,那fn方法就一直不會(huì)被執(zhí)行,按照這個(gè)思路改進(jìn)一下防抖函數(shù);
function _throttle(fn,wait,time){
var previous = null; //記錄上一次運(yùn)行的時(shí)間
var timer = null;
return function(){
var now = +new Date();
if(!previous) previous = now;
//當(dāng)上一次執(zhí)行的時(shí)間與當(dāng)前的時(shí)間差大于設(shè)置的執(zhí)行間隔時(shí)長(zhǎng)的話,就主動(dòng)執(zhí)行一次
if(now - previous > time){
clearTimeout(timer);
fn();
previous = now;// 執(zhí)行函數(shù)后,馬上記錄當(dāng)前時(shí)間
}else{
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait);
}
}
}
function fn(){
console.log(1)
}
window.onscroll = _throttle(fn,500,2000)
gitHub地址: https://github.com/DevilLittle/throttle