防抖(debounce):當持續觸發事件時,保證只執行最后一次事件處理函數
在給DOM綁定事件時,有些事件我們是無法控制觸發頻率的。
如鼠標移動事件onmousemove, 滾動滾動條事件onscroll,
窗口大小改變事件onresize,瞬間的操作都會導致這些事件會被高頻觸發。
如果事件的回調函數較為復雜,就會導致響應跟不上觸發,出現頁面卡頓,假死現象。
在實時檢查輸入時,如果我們綁定onkeyup事件發請求去服務端檢查,用戶輸入過程中,事件的觸發頻率也會很高,
會導致大量的請求發出,響應速度會大大跟不上觸發。
如何實現防抖呢?
我們拿滾動事件舉例子,用戶的滾動會頻繁觸發滾動事件,很容易造成頁面卡死。那么我們可以封裝如下一個函數。
每次想調用函數的時候,設置一個定時器讓函數延遲執行。
當連續觸發的時候,前面每次定時器都會清除掉,都會停掉前面的定時器所以函數並不會運行,只會執行最后一次。
// 防抖 function debounce(fn) { let timeout = null; // 創建一個標記用來存放定時器的返回值 return function () { clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉 timeout = setTimeout(() => { // 然后又創建一個新的 setTimeout, 這樣就能保證輸入字符后的 interval 間隔內如果還有字符輸入的話,就不會執行 fn 函數 fn() }, 500); }; } function sayHi() { console.log('防抖成功'); } let box = document.getElementById('box') box.addEventListener('click', debounce(sayHi))
節流(throttle)::當持續觸發事件時,保證一定時間段內只調用一次事件處理函數
如何實現節流?
當用戶連續操作的時候,我們設置一個定時器,一段時間后執行函數,並且執行完把標記改為true,所以在函數沒有執行完之前一直是false,
可能有的同學認為連續操作那么函數連續運行,那么canRun這個標記不一直是true嗎,
並不是,注意這里是一個閉包結構,真正每次調用的其實是throttle里面return的函數並不是每次都調用throttle,所以canRun只是提供初始值,並不會每次都重新賦值為true。
所以用戶連續操作的時候,比如用戶一秒鍾連續操作了十次,但是對於我們這個代碼來說,只可能每500毫秒執行一次,因為只有500ms之后canRun才為true,才能開啟下一個定時器。
所以哪怕用戶一秒鍾之內連續點了十次,其實也只是能執行兩次。這就符合節流的本意。
function throttle(fn) { let canRun = true; // 通過閉包保存一個標記 return function () { if (!canRun) return; // 在函數開頭判斷標記是否為true,不為true則return canRun = false; // 立即設置為false setTimeout(() => { // 將外部傳入的函數的執行放在setTimeout中 fn() // 最后在setTimeout執行完畢后再把標記設置為true(關鍵)表示可以執行下一次循環了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉 canRun = true; }, 500); }; } function sayHi(e) { console.log('節流'); } window.addEventListener('resize', throttle(sayHi));
總結:防抖動和節流本質是不一樣的。
防抖動是將多次執行變為最后一次執行,節流是將多次執行變成每隔一段時間執行。
文章轉載至https://blog.csdn.net/qq_40096030/article/details/114372174