在項目開發過程中經常遇到在input的change事件中發起請求,將用戶最新輸入的字符作為data傳給后台,但是如果用戶的輸入頻率過高,或者用戶輸入的字符還未拼成一個完整的字詞,這時候發起請求會浪費網絡資源,使頁面卡頓。
這時候我們就用到了函數去抖(debounce)和函數節流(throttle),首先來看一下概念:
1,函數去抖(又稱防抖)
在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。
未優化前代碼demo:
<input id="debounceTest" />
<script> function ajax(value) { console.log(value+'-----------發起ajax請求') } let inputa = document.getElementById('debounceTest') inputa.addEventListener('keyup', function (e) { ajax(e.target.value) }) </script>
效果圖:
從頁面中可以看到,只要觸發了keyup時間,頁面就會發起請求,不管用戶是否輸入了一個完整的字符,這樣對網絡資源十分浪費,在移動端甚至可能造成用戶體驗不流暢,系統卡頓,所以我們來對代碼進行優化,如下:
優化后代碼demo:
function ajax(content) { console.log(content+'---------------ajax請求') } function debounce(fun, delay) { return function (args) { let that = this let _args = args clearTimeout(fun.id) fun.id = setTimeout(function () { fun.call(that, _args) }, delay) } } let inputb = document.getElementById('debounce') let debounceAjax = debounce(ajax, 500) inputb.addEventListener('keyup', function (e) { debounceAjax(e.target.value) })
頁面效果:
可以看出,當用戶一直在輸入時,頁面不會發起請求,當用戶的上次輸入與下次輸入有一定時間間隔時,頁面才會發起請求。
同樣的問題還有另一種解決方法:
2,函數節流(throttle)
規定在一個單位時間內,只能觸發一次函數。如果這個單位時間內觸發多次函數,只有一次生效。
還是上邊的例子,這次用節流的方法實現
節流后的代碼demo:
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 inputc = document.getElementById('throttle') inputc.addEventListener('keyup', function(e) { throttleAjax(e.target.value) })
頁面效果:
可以看出,不管用戶的輸入速度是多少,頁面總是以恆定的間隔向后台發起請求。
函數節流還可以應用於其他事件,比如mouse移動事件,頁面滾動事件,resize事件等能高頻次觸發的事件中。
函數節流和去抖都是為了解決事件觸發頻率過高的問題,但是使用了不同的原理
節流是總是以固定的間隔發起請求,對高頻率事件做做次數限制。去抖是固定時間段內只發送一次請求。對高頻率事件做做次數限制
以上為節流去抖的全部內部,如有錯誤還望指正。