這是前端日常開發常用功能這個系列文章的第一篇,該系列是日常開發中一些常用的功能的再總結、再提煉,以防止遺忘,便於日后復習。該系列預計包含以下內容: 防抖、節流、去重、拷貝、最值、扁平、偏函數、柯里、惰性函數、遞歸、亂序、排序、注入、上傳、下載、截圖。。。
什么是防抖?
防抖就是對於頻繁觸發的事件添加一個延時同時設定一個最小觸發間隔,如果觸發間隔小於設定的間隔,則清除原來的定時,重新設定新的定時;如果觸發間隔大於設定間隔,則保留原來的定時,並設置新的定時;防抖的結果就是頻繁的觸發轉變為觸發一次
為什么要進行防抖?
在頻繁觸發事件的場景,有些情況可能執行的邏輯比較復雜或者耗時,此時瀏覽器的處理跟不上觸發,就會發生卡頓、假死或者事件堆積,這里防抖就可以一定程度上解決或者緩解這種故障。
常見的需要防抖的場景: 搜索框keyup、keydown等觸發后台請求; 頻繁改變窗口大小resize;鼠標移動mousemove事件;類似以上頻繁觸發並且處理邏輯較為耗時或者觸發時需要請求后台接口;
如何做到防抖呢?
版本1
<html> <head> <meta charset="UTF-8"> <style> div { width: 500px; height: 300px; background: orange; } </style> </head> <body> <div id="div"></div> </body> <script> const div = document.getElementById('div'); const debounce = (fn, wait) => { let timer; return function() { clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, arguments); }, wait); } }; const fn = debounce((e) => { console.log('move', e); }, 1000) div.addEventListener('mousemove', fn); </script> </html>
執行結果: 在橙色區域移動鼠標,只在停止移動后才會觸發一次事件;
如果我們想讓事件立即觸發一次呢?
版本2
<html> <head> <meta charset="UTF-8"> <style> div { width: 500px; height: 300px; background: orange; } </style> </head> <body> <div id="div"></div> </body> <script> const div = document.getElementById('div'); const debounce = (fn, wait, immediate = false) => { let timer; return function() { if(timer) clearTimeout(timer); if(immediate) { let trigger = !timer; timer = setTimeout(() => { timer = null; }, wait); if(trigger) { fn.apply(this, arguments); } return; } timer = setTimeout(() => { fn.apply(this, arguments); }, wait); return; } }; const fn = debounce((e) => { console.log('move', e); }, 1000, true) div.addEventListener('mousemove', fn); </script> </html>
執行結果是: 立即觸發一次,然后停止觸發1s后才能再次觸發
如果這個防抖時間比較長,比如是5s,我希望可以取消這種“掛起”狀態
<html> <head> <meta charset="UTF-8"> <style> div { width: 500px; height: 300px; background: orange; } </style> </head> <body> <div id="div"></div> <button id="btn">取消debounce</button> </body> <script> const div = document.getElementById('div'); const btn = document.getElementById('btn'); const debounce = (fn, wait, immediate = false) => { let timer; const debounced =function(){ if(timer) clearTimeout(timer); if(immediate) { let trigger = !timer; timer = setTimeout(() => { timer = null; }, wait); if(trigger) { fn.apply(this, arguments); } return; } timer = setTimeout(() => { fn.apply(this, arguments); }, wait); return; } debounced.cancel = () => { clearTimeout(timer); timer = null; } return debounced; }; const fn = debounce((e) => { console.log('move', e); }, 2000, true) div.addEventListener('mousemove', fn); btn.addEventListener('click', fn.cancel) </script> </html>
點擊一下按鈕就可以啦。
可能待完善。。。