定義
在JS里薪韩,有一些事件是很容易頻繁觸發(fā)的确沸,比如窗口的resize、scroll俘陷、鼠標(biāo)的onmousemove等操作罗捎,在事件頻繁觸發(fā)的過程中,不可避免的導(dǎo)致頻繁執(zhí)行觸發(fā)事件中的函數(shù)拉盾。為了防止這種情況的發(fā)生桨菜,主流的解決方案有兩種,防抖(debounce)和節(jié)流(throttle)
頻繁執(zhí)行情況
var num = 1;
var moveCntent = document.getElementById('example')
function count(){
moveCntent.innerHTML++;
}
moveCntent.onmousemove = count
效果如下:
可以明顯的看到捉偏,count 函數(shù)執(zhí)行的非常頻繁倒得,假如現(xiàn)在我們count函數(shù)里執(zhí)行的是一個Ajax請求,那么問題就會非常嚴重了告私。
防抖
函數(shù)防抖就是在一段時間(n毫秒)觸發(fā)或調(diào)用函數(shù)時,只執(zhí)行一次; 也可以理解為觸發(fā)n毫秒之后才會調(diào)用一次屎暇。
防抖函數(shù)的寫法主要有兩種,非立即執(zhí)行版本和立即執(zhí)行版本驻粟。
非立即執(zhí)行版
var num = 1;
var moveCntent = document.getElementById('example')
function count(){
moveCntent.innerHTML++;
}
moveCntent .onmousemove = count
function debounce(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(timer) clearTimeout(timeout);
timer = setTimeout(function(){
fn.apply(_this,args)
},delay)
}
}
moveCntent.onmousemove = debounce(count,1000)
原理是維護一個計時器,規(guī)定在delay時間后觸發(fā)函數(shù)蜀撑,但是在delay時間內(nèi)再次觸發(fā)的話挤巡,就會取消之前的計時器而重新設(shè)置酷麦。這樣一來,只有最后一次操作能被觸發(fā)沃饶。
效果如下:
在觸發(fā)事件1秒后才執(zhí)行,如果在觸發(fā)事件的一秒內(nèi)又觸發(fā)了事件糊肤,則重新計算函數(shù)執(zhí)行時間
立即執(zhí)行版
function debounce(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(timer){
clearTimeout(timer);
}
if(!timer){
fn.apply(_this,args);
}
timer = setTimeout(function(){
timer = null;
},delay);
};
}
立即執(zhí)行版本和非例行版本的區(qū)別是:
- 立即執(zhí)行版本:觸發(fā)事件后函數(shù)立即執(zhí)行琴昆,然后n秒內(nèi)不觸發(fā)時間才會繼續(xù)執(zhí)行
- 非立即執(zhí)行版本:觸發(fā)事件后函數(shù)不會立即執(zhí)行馆揉,而是在n秒回才會執(zhí)行
節(jié)流
函數(shù)節(jié)流,就是指連續(xù)觸發(fā)的事件在n秒鐘只執(zhí)行一次函數(shù)。降低函數(shù)的執(zhí)行頻率舷暮,對于函數(shù)節(jié)流,通常也也有兩種方式實現(xiàn)下面,分別是時間戳版和定時器版
時間戳版
function throttle(fn,delay){
var previous = 0;
return function(){
var now = Date.now();
var _this = this;
var args = arguments;
if(now - previous > delay){
fn.apply(_this,args);
previous = now;
}
};
}
moveCntent.onmousemove = throttle(count,1000)
當(dāng)高頻事件觸發(fā)時,第一次會立即執(zhí)行诸狭,而后再怎么頻繁地觸發(fā)事件券膀,也都是每delay時間才執(zhí)行一次驯遇。
效果如下:
持續(xù)觸發(fā)事件的過程中,函數(shù)會立即執(zhí)行叉庐,并且每一秒執(zhí)行一次
定時器版
function throttle(fn,delay){
var timer;
return function(){
var _this = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
timer = null;
fn.apply(_this,args);
},delay);
}
};
}
在持續(xù)觸發(fā)事件的過程中,函數(shù)不會立即執(zhí)行陡叠,并且每一秒執(zhí)行一次玩郊,停止觸發(fā)事件后枉阵,還會再執(zhí)行一次
效果如下:
時間戳版本和定時器版本的區(qū)別是:
- 時間戳版本:觸發(fā)事件后函數(shù)立即執(zhí)行译红,每n秒執(zhí)行一次
- 定時器版本:觸發(fā)事件后函數(shù)不會立即執(zhí)行,每n秒執(zhí)行一次兴溜,停止觸發(fā)后還會執(zhí)行一次
總結(jié)
函數(shù)防抖:將幾次操作合并為一此操作進行侦厚。原理是維護一個計時器,規(guī)定在delay時間后觸發(fā)函數(shù)拙徽,但是在delay時間內(nèi)再次觸發(fā)的話刨沦,就會取消之前的計時器而重新設(shè)置。這樣一來膘怕,只有最后一次操作能被觸發(fā)想诅。
函數(shù)節(jié)流:使得一定時間內(nèi)只觸發(fā)一次函數(shù)。原理是通過判斷是否到達一定時間來觸發(fā)函數(shù)岛心。
區(qū)別: 函數(shù)節(jié)流不管事件觸發(fā)有多頻繁来破,都會保證在規(guī)定時間內(nèi)一定會執(zhí)行一次真正的事件處理函數(shù),而函數(shù)防抖只是在最后一次事件后才觸發(fā)一次函數(shù)忘古。 比如在頁面的無限加載場景下徘禁,我們需要用戶在滾動頁面時,每隔一段時間發(fā)一次 Ajax 請求存皂,而不是在用戶停下滾動頁面操作時才去請求數(shù)據(jù)。這樣的場景,就適合用節(jié)流技術(shù)來實現(xiàn)旦袋。
轉(zhuǎn)自 http://www.reibang.com/p/35e6ed1642e4