
為什么要使用這兩種策略
在我們?nèi)粘5拈_發(fā)中,以下幾種情況會(huì)高頻率的觸發(fā)事件:
resizescrollclickmousemovekeydown
高頻率的觸發(fā)事件,會(huì)過度損耗頁面性能,導(dǎo)致頁面卡頓,頁面抖動(dòng),尤其是當(dāng)這些事件回調(diào)函數(shù)中包含ajax等異步操作的時(shí)候,多次觸發(fā)會(huì)導(dǎo)致返回的內(nèi)容結(jié)果順序不一致,而導(dǎo)致得到的結(jié)果非最后一次觸發(fā)事件對應(yīng)的結(jié)果。
兩種策略的工作方式
Debounce:一部電梯停在某一個(gè)樓層,當(dāng)有一個(gè)人進(jìn)來后,20秒后自動(dòng)關(guān)門,這20秒的等待期間,又一個(gè)人按了電梯進(jìn)來,這20秒又重新計(jì)算,直到電梯關(guān)門那一刻才算是響應(yīng)了事件。
Throttle:好比一臺自動(dòng)的飲料機(jī),按拿鐵按鈕,在出飲料的過程中,不管按多少這個(gè)按鈕,都不會(huì)連續(xù)出飲料,中間按鈕的響應(yīng)會(huì)被忽略,必須要等這一杯的容量全部出完之后,再按拿鐵按鈕才會(huì)出下一杯。
使用方式
這里我們使用 Lodash 庫里面實(shí)現(xiàn)的debouce和throttle方法。
lodash支持自定義封裝,使用下面兩個(gè)命令封裝一個(gè)我們自己的lodash庫。
$ npm i -g lodash-cli
$ lodash include=debouce,throttle
debounce調(diào)用方法:_.debounce(func, [wait=0], [options={}]) 返回一個(gè)具有debounce策略的新函數(shù)。
throttle調(diào)用方法:_.throttle(func, [wait=0], [options={}]) 返回一個(gè)具有throttle策略的新函數(shù)。
debounce參數(shù)列表
func (Function): The function to debounce.
[wait=0] (number): The number of milliseconds to delay.
[options={}] (Object): The options object.
[options.leading=false] (boolean): Specify invoking on the leading edge of the timeout.
[options.maxWait] (number): The maximum time func is allowed to be delayed before it's invoked.
[options.trailing=true] (boolean): Specify invoking on the trailing edge of the timeout.
下面的例子是在移動(dòng)端使用 rem 布局常用的一個(gè)函數(shù),偵聽resize事件改變根元素的fontSize,這種情況下適用debounce策略:
;(function (win, doc) {
let docEl = doc.documentElement;
const psdWidth = 750,
psdHeight = 1200,
aspect = psdWidth / psdHeight;
const recalc = function() {
const clientWidth = docEl.clientWidth;
const clientHeight = docEl.clientHeight;
if (!clientWidth) return;
if((clientWidth / clientHeight) > aspect) {
let ratio = clientWidth / psdWidth;
docEl.style.fontSize = 100 * ratio + 'px';
} else {
let ratio = clientHeight / psdHeight;
docEl.style.fontSize = 100 * ratio + 'px';
}
};
if (!doc.addEventListener) return;
const debounceRecalc = _.debounce(recalc, 200, {});
win.addEventListener('resize', debounceRecalc, false);
win.addEventListener('orientationchange', debounceRecalc, false);
debounceRecalc();
})(window, document)
這個(gè)例子中,使用throttle策略,點(diǎn)擊一次生成一行文字,1s中無論怎么點(diǎn)擊,都只生成一行文字:
;(function(){
let throttleBtn = document.querySelector('.throttle-click');
let text = document.querySelector('.show-text');
let clickHandler = _.throttle(function (){
text.innerHTML += '<p>do it.</p>';
console.log('do it.')
}, 1000, {});
throttleBtn.addEventListener('click', clickHandler);
})();
完整demo地址:demo