限流
在JS中,如果一個事件頻繁觸發(比如用戶瘋狂點擊按鈕)並且處理函數處理耗時還比較長,那么就容易造成性能問題。
限流函數是針對這類問題的優化方式之一,它要求兩次事件處理必須大於某個間隔時間,簡而言之就是加了一層判斷。
限流函數(throttle:節流閥)的核心在於內部維護了一個“上次執行時間點”,通過比較當前執行時間與上次執行時間的差值判斷是否“頻繁”,是否執行。限流函數本身是一個裝飾函數,修飾了事件處理器之后返回一個新的閉包函數。經過限流函數處理之后,事件觸發的頻率就被限制為預先傳入的interval之上了。
下面用代碼實現一個限流函數:
function throttle(fn, interval) {
// 維護上次執行的時間
let last = 0;
return function () {
const context = this;
const args = arguments;
const now = Date.now();
// 根據當前時間和上次執行時間的差值判斷是否頻繁
if (now - last >= interval) {
last = now;
fn.apply(context, args);
}
};
}
使用限流函數:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<button>click me</button>
<script src="./throttle.js"></script>
<script>
const button = document.querySelector("button");
button.addEventListener(
"click",
// 使用限流函數修飾事件處理器
throttle((event) => {
console.log("button click");
}, 2000)
);
</script>
</body>
</html>
防抖
防抖函數也是一種限流函數,但要特殊一些。最典型的場景是表單輸入,如果我們要在表單中監聽input事件(比如遠程搜索),那用戶在輸入的時候也會頻繁觸發,但這里使用throttle函數不行,因為我們需要等待用戶停止輸入一段時間后才能確認用戶輸入的值,所以要定義一個新的限流函數,叫做防抖函數。
防抖(防反跳)函數的核心是內部使用定時器並維護定時器返回的ID值,如果持續觸發則不斷clearTimeout()並重新發起setTimeout(),通過這種方式等待事件觸發完畢,然后進行延時處理。
下面用代碼實現一個防抖函數:
function debounce(fn, delay) {
// 記錄定時器返回的ID
let timer = null;
return function () {
const context = this;
const args = arguments;
// 當有事件觸發時清除上一個定時任務
if (timer) {
clearTimeout(timer);
}
// 重新發起一個定時任務
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
使用防抖函數:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<input type="text" />
<script src="debounce.js"></script>
<script>
const input = document.querySelector("input");
input.addEventListener(
"input",
debounce((event) => {
console.log("input finish");
}, 2000)
);
</script>
</body>
</html>
這些常用的函數可以參考lodash庫
總結
限流函數和防抖函數都是為了應對“事件處理的速度跟不上事件觸發的速度”這樣的場景而產生的優化函數。
限流(throttle)要求兩次事件處理之間必須有一個間隔時間,防抖(debounce)要求最后一個事件觸發完畢后再執行。