1.參考答案:
- 函數(shù)防抖和函數(shù)節(jié)流:優(yōu)化高頻率執(zhí)行js代碼的一種手段,js中的一些事件如瀏覽器的resize、scroll咱圆,鼠標(biāo)的mousemove、mouseover功氨,input輸入框的keypress等事件在觸發(fā)時(shí)序苏,會(huì)不斷地調(diào)用綁定在事件上的回調(diào)函數(shù),極大地浪費(fèi)資源捷凄,降低前端性能忱详。為了優(yōu)化體驗(yàn),需要對(duì)這類事件進(jìn)行調(diào)用次數(shù)的限制跺涤。
2.防抖:
- 在事件被觸發(fā)n秒后再執(zhí)行回調(diào)匈睁,如果在這n秒內(nèi)又被觸發(fā)管钳,則重新計(jì)時(shí)。
根據(jù)函數(shù)防抖思路設(shè)計(jì)出第一版的最簡單的防抖代碼:
var timer; // 維護(hù)同一個(gè)timer
function debounce(fn, delay) {
clearTimeout(timer);
timer = setTimeout(function(){
fn();
}, delay);
}
1.上面例子中的debounce就是防抖函數(shù)软舌,在document中鼠標(biāo)移動(dòng)的時(shí)候,會(huì)在onmousemove最后觸發(fā)的1s后執(zhí)行回調(diào)函數(shù)testDebounce牛曹;如果我們一直在瀏覽器中移動(dòng)鼠標(biāo)(比如10s)佛点,會(huì)發(fā)現(xiàn)會(huì)在10 + 1s后才會(huì)執(zhí)行testDebounce函數(shù)(因?yàn)閏learTimeout(timer)),這個(gè)就是函數(shù)防抖黎比。
2.在上面的代碼中超营,會(huì)出現(xiàn)一個(gè)問題,var timer只能在setTimeout的父級(jí)作用域中阅虫,這樣才是同一個(gè)timer演闭,并且為了方便防抖函數(shù)的調(diào)用和回調(diào)函數(shù)fn的傳參問題,我們應(yīng)該用閉包來解決這些問題颓帝。
優(yōu)化后的代碼:
function debounce(fn, delay) {
var timer; // 維護(hù)一個(gè) timer
return function () {
var _this = this; // 取debounce執(zhí)行作用域的this
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(_this, args); // 用apply指向調(diào)用debounce的對(duì)象米碰,相當(dāng)于_this.fn(args);
}, delay);
};
}
使用閉包后,解決傳參和封裝防抖函數(shù)的問題购城,這樣就可以在其他地方隨便將需要防抖的函數(shù)傳入debounce了吕座。
3.節(jié)流:
- 每隔一段時(shí)間,只執(zhí)行一次函數(shù)瘪板。
定時(shí)器實(shí)現(xiàn)節(jié)流函數(shù):
function throttle(fn, delay) {
var timer;
return function () {
var _this = this;
var args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null; // 在delay后執(zhí)行完fn之后清空timer吴趴,此時(shí)timer為假,throttle觸發(fā)可以進(jìn)入計(jì)時(shí)器
}, delay)
}
}
時(shí)間戳實(shí)現(xiàn)節(jié)流函數(shù):
function throttle(fn, delay) {
var previous = 0;
// 使用閉包返回一個(gè)函數(shù)并且用到閉包函數(shù)外面的變量previous
return function() {
var _this = this;
var args = arguments;
var now = new Date();
if(now - previous > delay) {
fn.apply(_this, args);
previous = now;
}
}
}
4.異同比較
相同點(diǎn):
- 都可以通過使用 setTimeout 實(shí)現(xiàn)侮攀。
- 目的都是锣枝,降低回調(diào)執(zhí)行頻率。節(jié)省計(jì)算資源兰英。
不同點(diǎn):
- 函數(shù)防抖撇叁,在一段連續(xù)操作結(jié)束后,處理回調(diào)箭昵,利用clearTimeout 和 setTimeout實(shí)現(xiàn)税朴。函數(shù)節(jié)流,在一段連續(xù)操作中家制,每一段時(shí)間只執(zhí)行一次正林,頻率較高的事件中使用來提高性能。
- 函數(shù)防抖關(guān)注一定時(shí)間連續(xù)觸發(fā)的事件只在最后執(zhí)行一次颤殴,而函數(shù)節(jié)流側(cè)重于一段時(shí)間內(nèi)只執(zhí)行一次觅廓。
常見應(yīng)用場景
5.函數(shù)防抖的應(yīng)用場景:
連續(xù)的事件,只需觸發(fā)一次回調(diào)的場景有:
- 搜索框搜索輸入涵但。只需用戶最后一次輸入完杈绸,再發(fā)送請(qǐng)求 手機(jī)號(hào)帖蔓、郵箱驗(yàn)證輸入檢測
- 窗口大小Resize。只需窗口調(diào)整完成后瞳脓,計(jì)算窗口大小塑娇。防止重復(fù)渲染。
6.函數(shù)節(jié)流的應(yīng)用場景:
間隔一段時(shí)間執(zhí)行一次回調(diào)的場景有:
- 滾動(dòng)加載劫侧,加載更多或滾到底部監(jiān)聽
- 谷歌搜索框埋酬,搜索聯(lián)想功能
- 高頻點(diǎn)擊提交,表單重復(fù)提交