函數節流和函數防抖是一種優化方法,可用於減小高頻繁觸發任務(函數)的執行次數,達到減小資源佔用的目的。jquery
咱們以滾動條的監聽事件爲例,首先看看使用函數節流和函數防抖前的現象。bash
let count = 0;
$(document).scroll(function () {
console.log(`觸發了${++count}次!`);
});
複製代碼
能夠看到隨着滾動條的拖動,滾動條拖動的回調函數被頻繁觸發,在回調比較複雜的時候,頻繁觸發的回調函數甚至會讓網頁出現掉幀的狀況。並且有些時候,業務上咱們並不須要這麼高頻繁的函數調用。這個時候咱們就能夠根據業務使用函數節流或函數防抖了。
實現閉包
let count = 0;
$(document).scroll(throttle(function () {
console.log(`觸發了${++count}次!`);
}, 500));
function throttle(fn, wait) {
let canRun = true;
return function () {
if (!canRun) {
return;
}
canRun = false;
setTimeout(() => {
fn.apply(this, arguments); //讓scroll的回調函數的this保持一致
canRun = true;
}, wait);
}
}
複製代碼
咱們指定了一個時間間隔500ms,規定500ms內滾動事件回調函數只能執行一次。函數節流的實現要點是,使用閉包存儲是否可執行標記,若是可執行則設置一個延遲函數,在延遲函數中重置可執行標記。app
實現dom
let count = 0;
$(document).scroll(deBounce(function () {
console.log(`觸發了${++count}次!`);
}, 500));
function deBounce(fn, interval) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() =>{
fn.apply(this, arguments);
}, interval);
}
}
複製代碼
咱們指定一個時間間隔500ms,規定滾動事件的回調函數,只有在事件觸發的間隔大於500ms時回調函數才執行。函數防抖的實現要點是,使用閉包存儲一個延遲函數編號(便於清空延遲函數),在事件觸發的時候,清空這個延遲函數,而且設置新的延遲函數。函數
上文函數節流和函數防抖的實現中,調用fn的時候都是用的fn.apply(this, arguments)調用,而不是fn()直接調用。主要緣由是爲了fn函數內的this與本來的事件回調函數綁定的this保持一致。 setTimeout()調用的代碼運行在與所在函數徹底分離的執行環境上。這會致使,這些代碼中包含的 this 關鍵字會指向 window (或全局)對象。所以在setTimeout中使用箭頭函數(箭頭的this綁定的是當前的詞法做用域)此時的詞法做用域爲scroll事件回調函數中綁定的this(jquery中強制this指向dom元素),再將fn函數內的this綁定爲這個this。咱們以函數防抖爲例看看這兩種的區別。學習
$(document).scroll(deBounce(function () {
console.log(this); //#document
}, 500));
function deBounce(fn, interval) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() =>{
fn.apply(this, arguments);
}, interval);
}
}
複製代碼
$(document).scroll(deBounce(function () {
console.log(this); //Window
}, 500));
function deBounce(fn, interval) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() =>{
fn();
}, interval);
}
}
複製代碼
$(document).scroll(deBounce(function () {
console.log(this); //Window
}, 500));
function deBounce(fn, interval) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(this, arguments);
}, interval);
}
}
複製代碼
但願本文對你們有所幫助,互相學習,一塊兒提升。轉載請註明原帖。優化