目錄
第一章 防抖
1.1 防抖(debounce)簡介
1.2 應用場景
1.3 實現思路
1.4 手撕防抖代碼
第二章 節流
2.1 節流(throttle)簡介
2.2?應用場景
2.3?實現思路
2.4 手撕節流代碼(方法:時間戳和計時器)
2.5 時間戳與計時器實現的區別
第三章 總結
第一章 防抖
1.1 防抖(debounce)簡介
- 場景:用戶在一段時間頻繁點擊執行某個函數/事件,那么在這段時間,用戶點擊一次,計時器重新計時,當在這段時間內用戶沒有觸發該函數/事件時,該函數/事件會在這段時間結束時執行。
- 應用示例理解:回城被打斷,玩家殘血準備回城,需要3s回城成功,但是在這個3s的過程中,玩家又重新點擊了回城,導致3s回城重新計算,再等3s。
1.2 應用場景
- 登錄、發短信、發送post請求等按鈕/事件避免用戶點擊太快,以致于發送了多次請求,需要防抖,最后一次發送請求即可;
- 調整瀏覽器窗口大小時,resize 次數過于頻繁,造成計算過多,此時需要一次到位,就用到了防抖;
- input輸入框獲取到value值不需要輸入一個字符就獲取一次,可以使用防抖,讓其輸入結束之后再獲取其值
- 文本編輯器實時保存,當無任何更改操作一秒后進行保存。
- ……
1.3 實現思路
?
1.4 手撕防抖代碼
function debounce(func,delay) {// 定義一個定時器timerlet timer = nullreturn function() {const that = thisconst args = arguments// 防抖核心:每次觸發事件計時器都會重新計時clearTimeout(timer)timer = setTimeout(()=>{func.apply(that,args)},delay)}
}
- 例子:
未調用防抖函數時:用戶每在input輸入/刪除一個值,都會輸出一個值;
<input type="text" id="input"><script>let inputDom = document.getElementById('input')//獲取輸入框的輸入內容inputDom.oninput = function(){console.log('this.value',this.value)}</script>
?
?
調用防抖函數后:用戶在input輸入/刪除一個值delay之后才,會輸出一個值
let inputDom = document.getElementById('input')//func 是執行函數,delay 是事件執行的延遲時間,毫秒function debounce(func,delay) {// 定義一個定時器timerlet timer = nullreturn function() {const that = thisconst args = arguments// 防抖核心:每次觸發事件計時器都會重新計時clearTimeout(timer)timer = setTimeout(()=>{func.apply(that,args)},delay)}}function handler() {console.log('this.value',this.value)}inputDom.addEventListener('input', debounce(handler, 1000))
第二章 節流
2.1 節流(throttle)簡介
- 場景:用戶在一段時間頻繁點擊執行某個函數/事件,那么在這段時間,用戶點擊一次/多次(調用事件),都不會影響計時器執行,并且該函數/事件只執行一次。
- 應用示例理解:技能冷卻中,玩家在某種情況下使用了閃現這個技能,但是這個技能的冷卻時間是120s,在這段時間里,玩家遇到危險,想要再使用閃現這個技能,頻繁的點擊它,但是并沒用,閃現不會執行,計時器依然還在倒計時,等到120s倒計時為0才能再使用一次閃現的技能。
2.2?應用場景
- 窗口調整
- 頁面滾動
- 搶購和瘋狂點擊
- 懶加載獲取滾動條的位置
- 鼠標連續不斷地觸發某事件(如點擊),只在規定時間內觸發一次
- ……
2.3?實現思路
2.4 手撕節流代碼(方法:時間戳和計時器)
// ---------------------節流1:使用時間戳---------------------
//func 是事件處理程序,delay 是事件執行的延遲時間,單位:毫秒
function throttle (func, delay) {//定義初始時間(開始觸發事件的時間)let start = 0;return function () {const that = thisconst args = arguments// 獲取當前時間戳let cur =Date.now()// 時間間隔大于延遲時間則進入if (cur - start >= delay) {//執行事件處理程序func.apply(that, args);//更新初始時間start = cur}}
}
// ---------------------節流2:使用定時器---------------------
//func 是事件處理程序,delay 是事件執行的延遲時間,單位:毫秒
function throttle(func, delay){// 自定義一個定時器var timer = null;return function(){var that = this;var args = arguments// timer為null表示可以發送請求了,否則還在請求中,不執行事件if(!timer){timer = setTimeout(function(){//執行事件處理程序func.call(that, args)//事件執行完后把定時器清除掉,下次觸發事件的時候再設置timer = null;}, delay)} }
}
- ?例子:
未調用節流函數時,每點擊一次按鈕,都會執行一次函數調用:
<button id="button1">發送了節流請求</button>
const button1Dom = document.getElementById('button1')
button1Dom.addEventListener('click',function(){console.log("節流:我發送了消息")
})
?使用節流函數之后,頻繁的點擊發送請求,它會在計時器結束之后再發,這段時間內點擊發送一次請求之后,不會再發送請求:
const button1Dom = document.getElementById('button1')
// ---------------------節流1:使用時間戳---------------------
//func 是事件處理程序,delay 是事件執行的延遲時間,單位:毫秒
function throttle (func, delay) {//定義初始時間(開始觸發事件的時間)let start = 0;return function () {const that = thisconst args = arguments// 獲取當前時間戳let cur =Date.now()// 時間間隔大于延遲時間則進入if (cur - start >= delay) {//執行事件處理程序func.apply(that, args);//更新初始時間start = cur}}
}
// ---------------------節流2:使用定時器---------------------
//func 是事件處理程序,delay 是事件執行的延遲時間,單位:毫秒
// function throttle(func, delay){
// // 自定義一個定時器
// var timer = null;
// return function(){
// var that = this;
// var args = arguments
// // timer為null表示可以發送請求了,否則還在請求中,不執行事件
// if(!timer){
// timer = setTimeout(function(){
// //執行事件處理程序
// func.call(that, args)
// //事件執行完后把定時器清除掉,下次觸發事件的時候再設置
// timer = null;
// }, delay)
// }
// }
// }
button1Dom.addEventListener('click',throttle(function(){console.log("節流:我發送了消息")
},1000))
頻繁的點擊,降低了發送的頻率:?
?
2.5 時間戳與計時器實現的區別
最明顯的區別就是在頻繁點擊的時候,會發現使用時間戳實現的節流會在調用的時候馬上執行,而使用計時器實現會在時間段結束時執行
第三章 總結
- 所謂防抖,就是指觸發事件后,在 n 秒后函數才會執行,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間;節流,就是指連續觸發事件,但是在 n 秒中只執行一次函數。
- 函數節流不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數,而函數防抖只是在最后一次事件后才觸發一次函數。