在進行窗口的resize纺涤、scroll译暂,輸入框內(nèi)容校驗等操作時,如果事件處理函數(shù)調(diào)用的頻率無限制外永,會加重瀏覽器的負擔,導致用戶體驗非常糟糕拧咳。此時我們可以采用debounce(防抖)和throttle(節(jié)流)的方式來減少調(diào)用頻率,同時又不影響實際效果骆膝。
函數(shù)防抖
函數(shù)防抖(debounce)
:當持續(xù)觸發(fā)事件時,一定時間段內(nèi)沒有再觸發(fā)事件阅签,事件處理函數(shù)才會執(zhí)行一次掐暮,如果設(shè)定的時間到來之前政钟,又一次觸發(fā)了事件路克,就重新開始延時养交。如下圖精算,持續(xù)觸發(fā)scroll
事件時碎连,并不執(zhí)行handle
函數(shù)灰羽,當1000
毫秒內(nèi)沒有觸發(fā)scroll
事件時破花,才會延時觸發(fā)scroll
事件。
一起來實現(xiàn)個簡單的
debounce
~
防抖debounce
代碼:
// 防抖
function debounce(fn,wait){
var timer = null;
return function(){
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(fn,wait);
}
}
function handle(){
console.log(Math.random());
}
// 滾動事件
window.addEventListener('scroll', debounce(handle, 1000));
當持續(xù)觸發(fā)scroll
事件時座每,事件處理函數(shù)handle
只在停止?jié)L動1000毫秒之后才會調(diào)用一次,也就是說在持續(xù)觸發(fā)scroll
事件的過程中峭梳,事件處理函數(shù)handle
一直沒有執(zhí)行。
函數(shù)節(jié)流
函數(shù)節(jié)流(throttle)
:當持續(xù)觸發(fā)事件時,保證一定時間段內(nèi)只調(diào)用一次事件處理函數(shù)葱椭。節(jié)流通俗解釋就比如我們水龍頭放水,閥門一打開孵运,水嘩嘩的往下流,秉著勤儉節(jié)約的優(yōu)良傳統(tǒng)美德治笨,我們要把水龍頭關(guān)小點驳概,最好是如我們心意按照一定規(guī)律在某個時間間隔內(nèi)一滴一滴的往下滴旷赖。如下圖顺又,持續(xù)觸發(fā)scroll
事件時等孵,并不立即執(zhí)行handle
函數(shù)稚照,每隔1000
毫秒才會執(zhí)行一次handle
函數(shù)俯萌。
函數(shù)節(jié)流主要有兩種實現(xiàn)方法:時間戳和定時器果录。接下來分別用兩種方法實現(xiàn)
throttle~
節(jié)流throttle代碼(時間戳):
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
當高頻事件觸發(fā)時绳瘟,第一次會立即執(zhí)行(給scroll事件綁定函數(shù)與真正觸發(fā)事件的間隔一般大于delay,如果你非要在網(wǎng)頁加載1000毫秒以內(nèi)就去滾動網(wǎng)頁的話糖声,我也沒辦法o(╥﹏╥)o)斤彼,而后再怎么頻繁地觸發(fā)事件蘸泻,也都是每delay時間才執(zhí)行一次琉苇。而當最后一次事件觸發(fā)完畢后悦施,事件也不會再被執(zhí)行了 (最后一次觸發(fā)事件與倒數(shù)第二次觸發(fā)事件的間隔小于delay并扇,為什么小于呢抡诞?因為大于就不叫高頻了呀(?▽?))穷蛹。
節(jié)流throttle代碼(定時器):
// 節(jié)流throttle代碼(定時器):
var throttle = function(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
總結(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)。