前戲 🌰
經過上一篇文章的總結,我們知道:短時間內高頻率地觸發事件,可能會導致不良後果。
具體到我們開發界來說,如果數據一致處於一種高頻率更新的狀態,那麼可能會引發的問題如下:
- 前後端數據交互頻率過高,導致流量浪費。
- 界面高頻率渲染更新,引發頁面延遲、卡頓或假死等狀況,影響體驗。
在進入正題之前,我們先來看下面這個例子:
<form action="" class="example-form">
<div>
<label for="name">名稱</label>
<input type="text"
name="name"
id="name"
placeholder="please input your name"
>
</div>
<div>
<label for="res">輸入</label>
<textarea type="multipart"
name="res"
id="res"
placeholder="這裏是每一次輸入的結果"
></textarea>
</div>
</form>
window.onload = () => {
const inputEle = document.querySelector("#name");
const resEle = document.querySelector("#res");
inputEle.addEventListener("input", function (event) {
console.log(this.value);
resEle.value += `\n${ this.value }`
});
}
在輸入框的 input 事件中,將該輸入框的當前值輸出在多行文本框中。可以看到,每輸入一個拼音字母,都會有一條輸出記錄,觸發頻率取決於人的打字速度。
新需求 🤬
假如,現在有這麼一個新需求,要我們在 input 事件中加入新的邏輯:將輸入框的當前值發往後臺進行存儲。
可以想象,這種情況下的前後端交互頻率該有多高,其中很多數據都是沒有必要即刻發送保存的,純屬浪費流量。
我們可以考慮對這個需求進行一下優化,只要控制一下交互頻率就好,主要有以下兩個方向:
- 每隔幾秒發送一次數據 —— 節流
- 每當用戶停止輸入之後,開始計時,一定時間後發送一次數據 —— 防抖
實現防抖
首先,我們從防抖的方向進行實現:只有當用戶停止輸入一段時間後,纔會將輸入內容輸出在多行文本框中。
window.onload = () => {
const resEle = document.querySelector("#res");
function changeOutputVal(value) {
resEle.value += `\n${ value }`;
}
function debounce(fn, delay = 1000) {
let timer = null;
return function (...args) {
console.log(args);
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
}
}
const outputRes = debounce(changeOutputVal, 1000);
const inputEle = document.querySelector("#name");
inputEle.addEventListener("input", (eve) => {
outputRes(eve.target.value);
});
}
代碼說明:
- 每一次事件被觸發,都會清除當前的 timer 然後重新設置超時調用,即重新計時。 這就會導致每一次高頻事件都會取消前一次的超時調用,導致事件處理程序不能被觸發;
- 只有當高頻事件停止,最後一次事件觸發的超時調用才能在delay時間後執行。
運行效果如下:
可以看到,在加入防抖代碼之後,input 事件並不會每次輸入都會輸出在多行文本,而是會在用戶停止輸入 delay 時間之後觸發輸出,頻率確實低了很多。從某種程度上來說,的確優化了頁面顯示效果,給人的視覺感受比較舒服。
總結
巧用防抖函數的,既可以優化性能,又能優化顯示效果,一舉兩得。
~
~
代碼比較粗糙,也比較基礎,後面會逐步向着複雜的方向迭代,望各位看官海涵🙏
~
~
~ 本文完
學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!
大家好!我是〖編程三昧〗的作者 隱逸王,我的公衆號是『編程三昧』,歡迎關注,希望大家多多指教!
知識與技能並重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!