throttle(函數節流) debounce(函數去抖) mutex(鎖)
Java等很多語言都有”鎖機制“,其實前端開發很多時候也需要“鎖”。例如:用戶連續點擊按鈕會多次觸發click事件、監聽鼠標滾動事件、監聽input框輸入事件...等都會需要“鎖”。今天,我就整理了有關前端“鎖”的相關知識,以供大家參考!
函數節流和去抖的出現場景,一般都伴隨着客戶端 DOM 的事件監聽。舉個例子,實現一個原生的拖拽功能(不能用 H5 Drag&Drop API),需要一路監聽 mousemove 事件,在回調中獲取元素當前位置,然後重置 dom 的位置(樣式改變)。如果我們不加以控制,每移動一定像素而觸發的回調數量是會非常驚人的,回調中又伴隨着 DOM 操作,繼而引發瀏覽器的重排與重繪,性能差的瀏覽器可能就會直接假死,這樣的用戶體驗是非常糟糕的。我們需要做的是降低觸發回調的頻率,比如讓它 500ms 觸發一次,或者 200ms,甚至 100ms,這個閾值不能太大,太大了拖拽就會失真,也不能太小,太小了低版本瀏覽器可能就會假死,這樣的解決方案就是函數節流,英文名字叫「throttle」。函數節流的核心是,讓一個函數不要執行得太頻繁,減少一些過快的調用來節流。
說完函數節流,再看它的好基友函數去抖(debounce)。思考這樣一個場景,對於瀏覽器窗口,每做一次 resize 操作,發送一個請求,很顯然,我們需要監聽 resize 事件,但是和 mousemove 一樣,每縮小(或者放大)一次瀏覽器,實際上會觸發 N 多次的 resize 事件,用節流?節流只能保證定時觸發,我們一次就好,這就要用去抖。簡單的說,函數去抖就是對於一定時間段的連續的函數調用,只讓其執行一次。
throttle 應用場景
函數節流有哪些應用場景?哪些時候我們需要間隔一定時間觸發回調來控制函數調用頻率?
- DOM 元素的拖拽功能實現(mousemove)
- 射擊遊戲的 mousedown/keydown 事件(單位時間只能發射一顆子彈)
- 計算鼠標移動的距離(mousemove)
- Canvas 模擬畫板功能(mousemove)
- 搜索聯想(keyup)
- 監聽滾動事件判斷是否到頁面底部自動加載更多:給 scroll 加了 debounce 後,只有用戶停止滾動後,纔會判斷是否到了頁面底部;如果是 throttle 的話,只要頁面滾動就會間隔一段時間判斷一次 #21 (comment)
debounce 應用場景
函數去抖有哪些應用場景?哪些時候對於連續的事件響應我們只需要執行一次回調?
- 每次 resize/scroll 觸發統計事件
- 文本輸入的驗證(連續輸入文字後發送 AJAX 請求進行驗證,驗證一次就好)
小結
函數節流和函數去抖的核心其實就是限制某一個方法被頻繁觸發,而一個方法之所以會被頻繁觸發,大多數情況下是因爲 DOM 事件的監聽回調,而這也是函數節流以及去抖多數情況下的應用場景。函數節流:間隔時間段觸發一次,函數去抖:只觸發一次,兩者有時候不需要細分,節流去抖也可以合在一起。
解決方法
方法一:加鎖
阻止連續點擊事件:申明一個變量,點擊時置灰提交按鈕。等接口調用結束放開按鈕。
<template>
<div>
<!-- 其他代碼 -->
<button v-if="canSave" @click="save">提交</button>
<button v-else disabled>提交</button>
</div>
</template>
<script>
export default {
data(){
return {
canSave: true,
}
},
methods: {
save(){
if(!canSave){
return;
}
this.canSave = false;
// AJAX 結束後 this.canSave = true;
},
}
}
</script>
方法二:
相關網址資料:https://segmentfault.com/q/1010000015296510
https://github.com/lessfish/underscore-analysis/issues/21
https://github.com/lessfish/underscore-analysis/issues/20
整合了一下資料,如有錯誤和問題,歡迎指正!