防抖和節流 (簡單易懂版)
序言
"什麼是防抖? 什麼是節流?"
在學習這兩個知識點的時候總是會容易搞混哪個是防抖,哪個是節流。
其分別又代表著什麼含義,對於在不同的開發需求中如何合理的運用這兩個知識點尤為重要。
一、防抖
防抖,顧名思義就是"防止抖動"。
放在按鈕的點選事件中即指: 在指定的時間內,你在不停的點選按鈕,按鈕所繫結的事件處理函式只會在最後一次執行。
也就是當你點選完按鈕後,在指定時間內沒有再次觸發這個按鈕的點選,則當指定的時間到了之後,事件的處理函式也就會執行。
假如有一天中午你剛在工地搬完二十車的磚頭,你隱約聽到了汽車的鳴笛聲。
是它來了,運鈔車。它承載著你這一年的辛勞和淚水,今天是發工資的日子。
忙碌了一上午,你的雙手已經疲憊不堪,你不緩不慢的放下了手上的二十塊磚頭。
走向了那堆滿鈔票的隊伍前,等待著領取那屬於你的勞動成果。
隨著時間的流逝,輪到你了。工頭指著那一堆說,那堆是你的。
你用手臂拂去額頭的汗水,憨笑道:"誒,好嘞!",然後你拿起桌上的簽字筆準備簽署。
當你正想簽名的時候,你的手臂不知覺的抖動了起來,你知道,這種狀態下是沒辦法簽字了。
你的雙眼凝視著你的手臂,它還在不停的抖動。你的眼角泛起了一絲輕蔑:"呵!防抖, 不過爾爾!"
然後,嘴中默唸道:
// 簡易防抖函式 function debounce(fn, delay) { let timer = null; return function() { if (timer) { clearTimeout(timer); timer= setTimeout(fn, delay); } else { timer = setTimeout(fn, delay); } }; } // 以下為示例程式碼: // 簽名 function signature(){ document.write('張三') } // 呼叫防抖函式 debounce(signature, 3000)()
時間一秒,兩秒,三秒...終於!它停止了...
你以迅雷不及掩耳耳之勢,瀟灑的簽上了你的大名----"張三"。
二、節流
節流,顧名思義就是節約流水
放在按鈕的點選事件中即指: 在指定的時間內,你還是在不停的點選按鈕,按鈕所繫結的事件處理函式只會執行一次。
換成技能的冷卻時間可能會更好理解些:你點選某個技能之後它會進入冷卻,在冷卻期間無法再次觸發這個技能。
時間回到你簽完名字時的前二十分鐘。
你放下磚頭之後,看了看滿是磚土的雙手,又看了看不遠處的水龍頭,嘆息道:"怎麼又停水了..."
你略作思考,便朝著工地對面的公廁走去。
來到公廁門口,你看到一名約是九歲左右的孩童在洗手池中玩耍。你略微皺眉,快步走上前去。
當你正要斥責孩童的不懂事的時候,那名孩童先於你開口說話了。"你可知,何謂節流?"
你一頭霧水的走過來,心中奇怪這孩童怎地在此處玩耍還愛自言自語?
待你走近,方知原來孩童玩耍的水池中並無水跡,便開始懷疑公廁是不是也停水了。
正當你還在疑慮之中時,孩童又說話了。"我知道哪裡有水,但閣下須回答我一個問題"
"什麼問題?"
"何謂節流?"
"不知,還望賜教",你再次皺起了眉頭,稍加思索後答道。
"謂之節流,即節約流水。"
"隔壁這個水池的水龍頭是好的,你且洗著手並聽我道來"
(你的內心):"Hai..."
"就像這個帶感應功能的水龍頭一樣,手放上去之後水龍頭就會釋放水流出來,但是當過幾秒後水流就會停止"
"這就是節約流水,你把手再放上去,水流亦會再次被釋放"
"你在幾秒內來回將手放在感應器上,水流並不會隨之快速釋放/暫停,大體相似於此:"
// 簡易節流函式 function throttle(fn, delay) { let valid = null; return () => { if (valid) { return false; } valid = true; setTimeout(() => { fn(); valid = false; }, delay); }; } // 以下為程式碼示例 // 釋放流水 function releaseWater() { return "水" } // 呼叫節流 throttle(releaseWater, 1500)()
聽到這裡,你彷彿猶如醍醐灌頂,轉瞬便明白了其中門道,順便還請教了下什麼是"防抖"。
總結:
①防抖:指定時間內,多次操作只取最後一次操作
②節流: 指定時間內,多次觸發操作只會執行第一次
節流和防抖都有很多種,比如下面的立即執行版節流,但是萬變不離其宗,知道核心原理便可以一法通時萬法通
// 節流 - 立即執行版 function throttleRightNow(fn, delay) { let valid = null; return () => { if (valid) { return false; } valid = true; fn(); setTimeout(() => { valid = false; }, delay); }; }