參考鏈接:https://juejin.im/post/5b651dc15188251aa30c8669
參考鏈接:https://www.jb51.net/article/158818.htm
在我們前端開發中,我們經常會需要綁定一些持續觸發的事件,如 resize、scroll、mousemove 等等,但有些時候我們並不希望在事件持續觸發的過程中那么頻繁地去執行函數。
通常這種情況下我們怎么去解決的呢?
一般來講,防抖和節流是比較好的解決方案。
函數節流(throttle)與 函數防抖(debounce)都是為了限制函數的執行頻次,以優化函數觸發頻率過高導致的響應速度跟不上觸發頻率,出現延遲,假死或卡頓的現象。
函數防抖
定義:就是指觸發事件后在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。舉個例子,當你在頁面中使用onkeyUp監聽用戶在input框中的輸入,如果用戶按住一個6不放,那監聽事件豈不是一直被觸發,這樣就浪費了一部分性能了,那么我們在一定事件內監聽,也就是說我過了一秒再來看看你輸入了多少個6,那這樣是不是輕松多了。
原理:維護一個計時器,規定在延時時間后觸發函數,但是在延時時間內再次被觸發的話,就取消之前的計時器而重新設置,這樣就能夠保證只有最后一次操作被觸發。即將所有操作合並為一個操作進行,並且只有最后一次操作是有效操作。
防抖函數分為非立即執行版和立即執行版。
非立即執行版:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>防抖</title>
</head>
<body>
<button id="debounce">防抖,防抖,防抖</button>
<script>
window.onload = function () {
let obtn = document.getElementById('debounce'); //獲取按鈕
obtn.addEventListener('click',debounceHandle(debounce,500),false); //監聽綁定事件
}
//防抖函數
function debounceHandle(func, delay) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);//如果存在事件就清除定時器
timer = setTimeout(() => {//如果不存在那么就開啟定時器
func.apply(this, args);
}, delay);
};
};
//執行函數
function debounce() {
console.log('防抖,這里可以寫一些防抖函數,如img中的onload事件');
}
</script>
</body>
</html>
立即執行版:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>防抖</title>
</head>
<body>
<button id="debounce">防抖,防抖,防抖</button>
<script>
window.onload = function () {
let obtn = document.getElementById('debounce'); //獲取按鈕
obtn.addEventListener('click',debounceHandle(debounce,500),false); //監聽綁定事件
}
//防抖函數
function debounceHandle(func, delay) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if(callNow) func.apply(this, args);
};
};
//執行函數
function debounce() {
console.log('防抖,這里可以寫一些防抖函數,如img中的onload事件');
}
</script>
</body>
</html>
上述防抖函數的代碼還需要注意的是 this 和 參數的傳遞。是為了讓 debounceHandle 函數最終返回的函數 this 指向不變以及依舊能接受到 e 參數。
函數節流
定義:當持續觸發事件時,保證一定時間段內只調用一次事件處理函數,按照一定的規律在某個時間間隔內去處理函數。假如在一個頁面中有任意多張圖片,那么就有可能會使用懶加載技術,譬如圖片的懶加載,我希望在下滑過程中圖片不斷的被加載出來,而不是只有當我停止下滑時候,圖片才被加載出來。那么節流就是在一定時間間隔內觸發一次事件。
原理:原理是通過判斷是否達到一定時間來觸發函數,使得一定時間內只觸發一次函數。
高頻事件觸發,但在n秒內只會執行一次,所以節流會稀釋函數的執行頻率
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>節流</title>
<style>
div {
height: 5000px;
}
</style>
</head>
<body>
<div>節流,節流,節流</div>
<script>
window.onload = function () {
window.addEventListener('scroll',throttleHandle(throttle),false); //監聽綁定事件
}
//節流函數
function throttleHandle (fn) {
let timer = null,
booleanVal = true; // 聲明一個變量標志做判斷
return function () {
if (!booleanVal) {
return
} //如果事件正在執行,那么就返回,將布爾值改為false
booleanVal = false;
//事件未執行,創建事件
timer = setTimeout(function() {
fn.apply(this,arguments);
booleanVal = true; //事件執行完將布爾值改回
},300)
}
}
//執行函數
function throttle() {
var scrollNum = document.documentElement.scrollTop || document.body.scrollTop;
console.log(scrollNum);
}
</script>
</body>
</html>
