前言
在類似scroll、resize事件中執行大量DOM操作或者計算時,就會出現再次觸發事件而上一次事件中的DOM操作和計算還沒完成的情況,結果瀏覽器掉幀了,導致性能下降,影響用戶體驗。而函數節流和函數防抖,兩者都是優化高頻率執行js代碼的一種手段。因此,可以用以下兩種方式優化代碼。
概念
一、函數防抖:
指頻繁觸發的情況下,只有足夠的空閑時間,才執行代碼一次,也就是讓某個函數在上一次執行后, 滿足等待某個時間內不再觸發此函數后再執行, 而在這個等待時間內再次觸發此函數, 等待時間會重新計算.實際需求多數為停止操作n毫秒后執行后續處理 。
二、函數節流:
指為這個操作(函數)預先設定一個執行周期,當調用動作的時刻>=執行周期則執行該動作,然后進入下一個新周期,否則不執行。簡單來說就是你的js方法在一定時間內只跑一次(頻率)。
適用場景
一、函數節流:
場景一:頁面元素滾動的時候,觸發某個事件。
場景二:高頻率點擊表單提交按鈕,表單重復提交。
實現要點:聲明一個變量當標志位,記錄當前代碼是否在執行,
var valve = true; //標志位
document.getElementById("box").onscroll = function(){
// 判斷是否已空閑,如果在執行中,則直接return,如果空閑,則可以正常觸發方法執行。
if(!valve){
return;
}
valve = false; //關閉
//要執行的函數
something()
};
function something(){
setTimeout(function(){
console.log("函數節流");
valve = true;//執行周期完成后打開閥門,允許再次調用
}, 300);
}
二、函數防抖:
場景一:表單驗證,用戶停止輸入后,然后開啟驗證
場景二:輪播圖等
實現要點:巧用setTimeout做緩存池,可以輕易地清除待執行的代碼。
// 函數防抖
var timer = false;
document.getElementById("box").onscroll = function(){
clearTimeout(timer); // 清除未執行的代碼,重置回初始化狀態
timer = setTimeout(function(){
//滾動事件停止300毫秒后 調用
console.log("函數防抖");
}, 300);
};
案例
一(防抖)、假設網站有個搜索框, 用戶輸入文本我們會自動聯想匹配出一些結果供用戶選擇,我們可能首先想到的做法就是監聽keypress事件, 然后異步查詢結果. 但是如果用戶快速的輸入了一串字符, 假設是10個字符, 那么就會在瞬間觸發10次請求, 這無疑不是我們想要的, 我們想要的是用戶停止輸入的時候才去觸發查詢的請求.
二(防抖vs節流)
假設網站有登錄框, 用戶登錄信息后,自動驗證用戶信息,首先監聽輸入框oninput事件, 然后異步驗證登錄信息.驗證成功點擊登錄按鈕,進行登錄操作。 但是這樣的話用戶每輸入了個字符, 就會調用一次oninput事件,那么就觸發1次請求, 這無疑不是我們想要的, 我們想要的是用戶停止輸入的時候才去觸發驗證的請求.(##這里可以用函數防抖處理 ,幾百毫秒后執行驗證信息##)
驗證成功后,進行登錄操作,調用登錄接口,但是如果高頻率點擊登錄按鈕,會不停調用登錄接口,(##這里可以用函數節流處理 ,在上次登錄接口調用完成之前,不能再次調用##)