在前端開發中,我們會遇到一些需要持續觸發的事件或者一些持續的請求,但是我們不希望在事件觸發時過於頻繁的去執行函式。
所以這個時候,就出現了函式防抖和函式節流的解決方案。
下面通過這樣一個場景來說明:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函式防抖和函式節流</title>
</head>
<body>
<div id="content" style="height:150px;line-height:150px;text-align:center; color: #ff1e1e;background-color:#3cccc7;font-size:80px;"></div>
<script type="text/javascript">
let num = 1;
let content = document.getElementById('content');
function count() {
content.innerHTML = num++;
};
content.onmousemove = count;
</script>
</body>
</html>
複製程式碼
在上述程式碼中,div 元素繫結了 mousemove
事件,當滑鼠在div區域中移動的時候會持續地去觸發該事件導致頻繁執行函式。
可以看到,在沒有通過其它操作的情況下,函式被頻繁地執行導致頁面上資料變化特別快。所以,接下來讓我們來看看防抖和節流是如何去解決這個問題的。
函式防抖(debounce)
函式防抖就是在觸發事件後 N 秒內函式只能執行一次,如果在 N 秒內又觸發了事件,則重新開始計算函式執行時間
函式防抖分為立即執行和非立即執行兩種
- 函式防抖--非立即執行
//非立即執行
function debounce(fun, delay) {
let timeout; //需要一個外部變數,為增強封裝,所以使用閉包
return function () {
let _this = this;
let arg = arguments; //arguments中存著e
if (timeout) clearTimeout(timeout);
timeout = setTimeout(()=> {
fun.apply(_this,arg);
},delay)
}
}
複製程式碼
非立即執行版的意思是觸發事件後函式不會立即執行,而是在 n 秒後執行,如果在 n 秒內又觸發了事件,則會重新計算函式執行時間。
我們依舊使用上述繫結 mousemove 事件的例子,通過上面的防抖函式,我們可以這麼使用
content.onmousemove = debounce(count,1000);
複製程式碼
可以看到,在觸發事件後函式 1 秒後才執行,而如果我在觸發事件後的 1 秒內又觸發了事件,則會重新計算函式執行時間。
- 函式防抖--立即執行
//立即執行
function debounce(fun, delay) {
let timeout;
return function () {
let _this = this;
let arg = arguments;
if (timeout) clearTimeout(timeout);
let applyNow = !timeout;
timeout = setTimeout(()=> {
timeout = null;
},delay)
if(applyNow) fun.apply(_this,arg);
}
}
複製程式碼
立即執行版的意思是觸發事件後函式會立即執行,然後 n 秒內不觸發事件才能繼續執行函式的效果。
開發過程中的需求是多樣的,為了適應各種需求,我們可以把上面兩種情況都封裝到一個方法裡,根據實際情況選擇呼叫。
function debounce(fun, delay, immediate) {
//immediate為true時立即執行,反之為非立即執行
let timeout;
return function () {
let _this = this;
let arg = arguments;
if (timeout) clearTimeout(timeout);
if(immediate){
//立即執行
let applyNow = !timeout;
timeout = setTimeout(()=> {
timeout = null;
},delay)
if(applyNow) fun.apply(_this,arg);
}else{
//非立即執行
timeout = setTimeout(()=>{
fun.apply(_this,arg);
},delay)
}
}
}
複製程式碼
函式節流(throttle)
函式節流是指在連續觸發事件時函式在 N 秒內只執行一次,節流會稀釋函式的執行頻率
一般有兩種方式可以實現,分別是時間戳版和定時器版。
- 函式防抖--時間戳版
//時間戳版
function throttle(fun, delay) {
let previous = 0;
return function () {
let _this = this;
let arg = arguments;
let now = Date.now();
console.log(now);
if(now - previous > delay){
fun.apply(_this,arg);
previous = now;
}
}
}
複製程式碼
- 函式防抖--定時器版
//定時器版
function throttle(fun, delay) {
let timeout;
return function () {
let _this = this;
let arg = arguments;
if(!timeout){
timeout = setTimeout(()=>{
timeout = null;
fun.apply(_this,arguments);
},delay)
}
}
}
複製程式碼