本文由小芭樂發表
0. 引入
首先舉一個例子:
模擬在輸入框輸入后做ajax查詢請求,沒有加入防抖和節流的效果,這里附上完整可執行代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>沒有防抖</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = function () {
//模擬ajax請求
function ajax(content) {
console.log('ajax request ' + content)
}
let inputNormal = document.getElementById('normal');
inputNormal.addEventListener('keyup', function (e) {
ajax(e.target.value)
})
}
</script>
</head>
<body>
<div>
1.沒有防抖的輸入:
<input type="text" name="normal" id="normal">
</div>
</body>
</html>
效果:在輸入框里輸入一個,就會觸發一次“ajax請求”(此處是console)。
沒有防抖和節流
缺點:浪費請求資源,可以加入防抖和節流來優化一下。
本文會分別介紹什么是防抖和節流,它們的應用場景,和實現方式。防抖和節流都是為了解決短時間內大量觸發某函數而導致的性能問題,比如觸發頻率過高導致的響應速度跟不上觸發頻率,出現延遲,假死或卡頓的現象。但二者應對的業務需求不一樣,所以實現的原理也不一樣,下面具體來看看吧。
1. 防抖(debounce)
1.1 什么是防抖
在事件被觸發n秒后再執行回調函數,如果在這n秒內又被觸發,則重新計時。
1.2 應用場景
(1) 用戶在輸入框中連續輸入一串字符后,只會在輸入完后去執行最后一次的查詢ajax請求,這樣可以有效減少請求次數,節約請求資源;
(2) window的resize、scroll事件,不斷地調整瀏覽器的窗口大小、或者滾動時會觸發對應事件,防抖讓其只觸發一次;
1.3 實現
還是上述列子,這里加入防抖來優化一下,完整代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>加入防抖</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = function () {
//模擬ajax請求
function ajax(content) {
console.log('ajax request ' + content)
}
function debounce(fun, delay) {
return function (args) {
//獲取函數的作用域和變量
let that = this
let _args = args
//每次事件被觸發,都會清除當前的timeer,然后重寫設置超時調用
clearTimeout(fun.id)
fun.id = setTimeout(function () {
fun.call(that, _args)
}, delay)
}
}
let inputDebounce = document.getElementById('debounce')
let debounceAjax = debounce(ajax, 500)
inputDebounce.addEventListener('keyup', function (e) {
debounceAjax(e.target.value)
})
}
</script>
</head>
<body>
<div>
2.加入防抖后的輸入:
<input type="text" name="debounce" id="debounce">
</div>
</body>
</html>
代碼說明:
1.每一次事件被觸發,都會清除當前的 timer 然后重新設置超時調用,即重新計時。 這就會導致每一次高頻事件都會取消前一次的超時調用,導致事件處理程序不能被觸發;
2.只有當高頻事件停止,最后一次事件觸發的超時調用才能在delay時間后執行;
效果:
加入防抖后,當持續在輸入框里輸入時,並不會發送請求,只有當在指定時間間隔內沒有再輸入時,才會發送請求。如果先停止輸入,但是在指定間隔內又輸入,會重新觸發計時。
加入防抖
2.節流(throttle)
2.1 什么是節流
規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,如果在同一個單位時間內某事件被觸發多次,只有一次能生效。
2.2 應用場景
(1)鼠標連續不斷地觸發某事件(如點擊),只在單位時間內只觸發一次;
(2)在頁面的無限加載場景下,需要用戶在滾動頁面時,每隔一段時間發一次 ajax 請求,而不是在用戶停下滾動頁面操作時才去請求數據;
(3)監聽滾動事件,比如是否滑到底部自動加載更多,用throttle來判斷;
2.3 實現
還是上述列子,這里加入節流來優化一下,完整代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>加入節流</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = function () {
//模擬ajax請求
function ajax(content) {
console.log('ajax request ' + content)
}
function throttle(fun, delay) {
let last, deferTimer
return function (args) {
let that = this;
let _args = arguments;
let now = +new Date();
if (last && now < last + delay) {
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fun.apply(that, _args);
}, delay)
} else {
last = now;
fun.apply(that, _args);
}
}
}
let throttleAjax = throttle(ajax, 1000)
let inputThrottle = document.getElementById('throttle')
inputThrottle.addEventListener('keyup', function (e) {
throttleAjax(e.target.value)
})
}
</script>
</head>
<body>
<div>
3.加入節流后的輸入:
<input type="text" name="throttle" id="throttle">
</div>
</body>
</html>
效果:實驗可發現在持續輸入時,會安裝代碼中的設定,每1秒執行一次ajax請求
加入節流
3. 小結
總結下防抖和節流的區別:
-- 效果:
函數防抖是某一段時間內只執行一次;而函數節流是間隔時間執行,不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數。
-- 原理:
防抖是維護一個計時器,規定在delay時間后觸發函數,但是在delay時間內再次觸發的話,都會清除當前的 timer 然后重新設置超時調用,即重新計時。這樣一來,只有最后一次操作能被觸發。
節流是通過判斷是否到達一定時間來觸發函數,若沒到規定時間則使用計時器延后,而下一次事件則會重新設定計時器。
如有問題,歡迎指正。
此文已由作者授權騰訊雲+社區發布,更多原文請點擊
搜索關注公眾號「雲加社區」,第一時間獲取技術干貨,關注后回復1024 送你一份技術課程大禮包!