在開發中,我們常常會去監聽滾動事件或者用戶輸入框驗證事件,如果事件處理沒有頻率限制,就會加重瀏覽器的負擔,影響用戶的體驗感,
因此,我們可以采取防抖(debounce)和節流(throttle)來處理,減少調用事件的頻率,達到較好的用戶體驗。
防抖(debounce):
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 200px; height: 200px; overflow: auto; } </style> </head> <body> <div class="box" id="container"> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> <p>防抖演示</p> </div> </body>
function debounce(fn, wait) { var timeout = null;// 使用閉包,緩存變量 return function() { if(timeout !== null) { console.log('清除定時器啦') clearTimeout(timeout); //清除這個定時器 } timeout = setTimeout(fn, wait); } } // 處理函數 function handle() { console.log(Math.random()); } var container = document.getElementById('container') container.addEventListener('scroll', debounce(handle, 1000));
我們可以發現,當連續觸發scroll事件,handle函數只會在1秒時間內執行一次,在如果繼續滾動執行,就會清除定時器,重新計時。相當於就是多次執行,只執行一次。
節流(throttle):
var throttle = function(func, delay) { var timer = null; // 使用閉包,緩存變量 var prev = Date.now(); // 最開始進入滾動的時間 return function() { var context = this; // this指向window var args = arguments; var now = Date.now(); var remain = delay - (now - prev); // 剩余時間 clearTimeout(timer); // 如果剩余時間小於0,就立刻執行 if (remain <= 0) { func.apply(context, args); prev = Date.now(); } else { timer = setTimeout(func, remain); } } } function handle() { console.log(Math.random()); } var container = document.getElementById('container') container.addEventListener('scroll', throttle(handle, 1000));
在節流函數內部使用開始時間prev、當前時間now和剩余時間remain,當剩余時間小於等於0意味着執行處理函數,這樣保證第一次就能立即執行函數並且每隔delay時間執行一次;
如果還沒到時間,就會在remaining之后觸發,保證最后一次觸發事件也能執行函數,如果在remaining時間內又觸發了滾動事件,那么會取消當前的計數器並計算出新的remaing時間。
通過時間戳和定時器的方法,我們實現了第一次立即執行,最后一次也執行,規定時間間隔執行的效果。
總結,看完了防抖和節流的分別介紹,我們來看看他們的區別:
- 函數防抖和函數節流都是防止某一時間頻繁觸發,但是這兩兄弟之間的原理卻不一樣。
防抖是將多次執行變為只執行一次,節流是將多次執行變為每隔一段時間執行。
結合應用場景
防抖(debounce)
search搜索聯想,用戶在不斷輸入值時,用防抖來節約請求資源。
window觸發resize的時候,不斷的調整瀏覽器窗口大小會不斷的觸發這個事件,用防抖來讓其只觸發一次
節流(throttle)
鼠標不斷點擊觸發,mousedown(單位時間內只觸發一次)
監聽滾動事件,比如是否滑到底部自動加載更多,用throttle來判斷