js防抖和節(jié)流的深入講解
前言:
我們在做頁面事件綁定的時(shí)候,經(jīng)常要進(jìn)行節(jié)流處理,比如鼠標(biāo)異步點(diǎn)擊,去執(zhí)行一個(gè)異步請求時(shí),需要讓它在上一次沒執(zhí)行時(shí)不能再點(diǎn)擊,又或者綁定滾動(dòng)事件,這種持續(xù)觸發(fā)進(jìn)行dom判斷的時(shí)候,就要按一定頻率的執(zhí)行。
本文主要給大家介紹了關(guān)于js防抖和節(jié)流的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧
0. 引入
首先舉一個(gè)例子:
模擬在輸入框輸入后做ajax查詢請求,沒有加入防抖和節(jié)流的效果,這里附上完整可執(zhí)行代碼:
<!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>
效果:在輸入框里輸入一個(gè),就會觸發(fā)一次“ajax請求”(此處是console)。

沒有防抖和節(jié)流
缺點(diǎn):浪費(fèi)請求資源,可以加入防抖和節(jié)流來優(yōu)化一下。
本文會分別介紹什么是防抖和節(jié)流,它們的應(yīng)用場景,和實(shí)現(xiàn)方式。防抖和節(jié)流都是為了解決短時(shí)間內(nèi)大量觸發(fā)某函數(shù)而導(dǎo)致的性能問題,比如觸發(fā)頻率過高導(dǎo)致的響應(yīng)速度跟不上觸發(fā)頻率,出現(xiàn)延遲,假死或卡頓的現(xiàn)象。但二者應(yīng)對的業(yè)務(wù)需求不一樣,所以實(shí)現(xiàn)的原理也不一樣,下面具體來看看吧。
1. 防抖(debounce)
1.1 什么是防抖
在事件被觸發(fā)n秒后再執(zhí)行回調(diào)函數(shù),如果在這n秒內(nèi)又被觸發(fā),則重新計(jì)時(shí)。
1.2 應(yīng)用場景
(1) 用戶在輸入框中連續(xù)輸入一串字符后,只會在輸入完后去執(zhí)行最后一次的查詢ajax請求,這樣可以有效減少請求次數(shù),節(jié)約請求資源;
(2) window的resize、scroll事件,不斷地調(diào)整瀏覽器的窗口大小、或者滾動(dòng)時(shí)會觸發(fā)對應(yīng)事件,防抖讓其只觸發(fā)一次;
1.3 實(shí)現(xiàn)
還是上述列子,這里加入防抖來優(yōu)化一下,完整代碼如下:
<!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) {
//獲取函數(shù)的作用域和變量
let that = this
let _args = args
//每次事件被觸發(fā),都會清除當(dāng)前的timeer,然后重寫設(shè)置超時(shí)調(diào)用
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.每一次事件被觸發(fā),都會清除當(dāng)前的 timer 然后重新設(shè)置超時(shí)調(diào)用,即重新計(jì)時(shí)。 這就會導(dǎo)致每一次高頻事件都會取消前一次的超時(shí)調(diào)用,導(dǎo)致事件處理程序不能被觸發(fā);
2.只有當(dāng)高頻事件停止,最后一次事件觸發(fā)的超時(shí)調(diào)用才能在delay時(shí)間后執(zhí)行;
效果:
加入防抖后,當(dāng)持續(xù)在輸入框里輸入時(shí),并不會發(fā)送請求,只有當(dāng)在指定時(shí)間間隔內(nèi)沒有再輸入時(shí),才會發(fā)送請求。如果先停止輸入,但是在指定間隔內(nèi)又輸入,會重新觸發(fā)計(jì)時(shí)。

加入防抖
2.節(jié)流(throttle)
2.1 什么是節(jié)流
規(guī)定一個(gè)單位時(shí)間,在這個(gè)單位時(shí)間內(nèi),只能有一次觸發(fā)事件的回調(diào)函數(shù)執(zhí)行,如果在同一個(gè)單位時(shí)間內(nèi)某事件被觸發(fā)多次,只有一次能生效。
2.2 應(yīng)用場景
(1)鼠標(biāo)連續(xù)不斷地觸發(fā)某事件(如點(diǎn)擊),只在單位時(shí)間內(nèi)只觸發(fā)一次;
(2)在頁面的無限加載場景下,需要用戶在滾動(dòng)頁面時(shí),每隔一段時(shí)間發(fā)一次 ajax 請求,而不是在用戶停下滾動(dòng)頁面操作時(shí)才去請求數(shù)據(jù);
(3)監(jiān)聽滾動(dòng)事件,比如是否滑到底部自動(dòng)加載更多,用throttle來判斷;
2.3 實(shí)現(xiàn)
還是上述列子,這里加入節(jié)流來優(yōu)化一下,完整代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>加入節(jié)流</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.加入節(jié)流后的輸入:
<input type="text" name="throttle" id="throttle">
</div>
</body>
</html>
效果:實(shí)驗(yàn)可發(fā)現(xiàn)在持續(xù)輸入時(shí),會安裝代碼中的設(shè)定,每1秒執(zhí)行一次ajax請求

加入節(jié)流
3. 小結(jié)
總結(jié)下防抖和節(jié)流的區(qū)別:
-- 效果:
函數(shù)防抖是某一段時(shí)間內(nèi)只執(zhí)行一次;而函數(shù)節(jié)流是間隔時(shí)間執(zhí)行,不管事件觸發(fā)有多頻繁,都會保證在規(guī)定時(shí)間內(nèi)一定會執(zhí)行一次真正的事件處理函數(shù)。
-- 原理:
防抖是維護(hù)一個(gè)計(jì)時(shí)器,規(guī)定在delay時(shí)間后觸發(fā)函數(shù),但是在delay時(shí)間內(nèi)再次觸發(fā)的話,都會清除當(dāng)前的 timer 然后重新設(shè)置超時(shí)調(diào)用,即重新計(jì)時(shí)。這樣一來,只有最后一次操作能被觸發(fā)。
節(jié)流是通過判斷是否到達(dá)一定時(shí)間來觸發(fā)函數(shù),若沒到規(guī)定時(shí)間則使用計(jì)時(shí)器延后,而下一次事件則會重新設(shè)定計(jì)時(shí)器。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- 如何在面試中手寫出javascript節(jié)流和防抖函數(shù)
- js節(jié)流防抖應(yīng)用場景,以及在vue中節(jié)流防抖的具體實(shí)現(xiàn)操作
- js防抖函數(shù)和節(jié)流函數(shù)使用場景和實(shí)現(xiàn)區(qū)別示例分析
- JS防抖和節(jié)流實(shí)例解析
- 深入了解JavaScript 防抖和節(jié)流
- JS中的防抖與節(jié)流及作用詳解
- JS函數(shù)節(jié)流和防抖之間的區(qū)分和實(shí)現(xiàn)詳解
- JS函數(shù)節(jié)流和函數(shù)防抖問題分析
- JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別
- JavaScript 防抖和節(jié)流遇見的奇怪問題及解決
相關(guān)文章
JavaScript數(shù)據(jù)結(jié)構(gòu)之雙向鏈表和雙向循環(huán)鏈表的實(shí)現(xiàn)
本篇文章主要介紹了JavaScript數(shù)據(jù)結(jié)構(gòu)之雙向鏈表和雙向循環(huán)鏈表的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
JavaScript實(shí)現(xiàn)氣球打字的小游戲
這篇文章主要介紹了JavaScript實(shí)現(xiàn)氣球打字的小游戲,下面文章的思路來源于打字游戲,具體實(shí)現(xiàn)過程,需要的朋友可以參考一下,希望對你的學(xué)習(xí)有所幫助2022-04-04
JavaScript?error瀏覽器端錯(cuò)誤捕獲處理方法筆記解決示例
這篇文章主要為大家介紹了JavaScript?error瀏覽器端錯(cuò)誤捕獲處理方法筆記解決示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
underscore之function_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
因?yàn)閡nderscore本來就是為了充分發(fā)揮JavaScript的函數(shù)式編程特性,所以也提供了大量JavaScript本身沒有的高階函數(shù)。本文重點(diǎn)給大家介紹underscore之function知識,感興趣的的朋友一起學(xué)習(xí)吧2017-07-07
uniapp實(shí)現(xiàn)點(diǎn)擊出現(xiàn)彈窗功能實(shí)例
這篇文章主要給大家介紹了關(guān)于uniapp實(shí)現(xiàn)點(diǎn)擊出現(xiàn)彈窗功能的相關(guān)資料,UniApp框架中提供了兩種不同類型的彈出框,以幫助我們滿足不同的需求,需要的朋友可以參考下2023-08-08
js點(diǎn)擊文本框后才加載驗(yàn)證碼實(shí)例代碼
這篇文章是一段關(guān)于js點(diǎn)擊文本框后才加載驗(yàn)證碼實(shí)例代碼,而不是直接顯示驗(yàn)證碼,感興趣的小伙伴們可以參考一下2015-10-10

