淺談JavaScript節(jié)流與防抖
節(jié)流與防抖
背景:當(dāng)我們頻繁去請(qǐng)求資源、接口等其他的時(shí)候,就會(huì)造成操作Dom頻繁,接口壓力大等等,性能下降。比如我有時(shí)候會(huì)每次搜索會(huì)猛地敲回車,在網(wǎng)絡(luò)不很好的時(shí)候,點(diǎn)擊下一頁(yè)按鈕的時(shí)候也會(huì)一直點(diǎn),可能網(wǎng)絡(luò)不好也可能服務(wù)器性能低。
為了避免頻繁觸發(fā)同一事件或請(qǐng)求,這時(shí)候就要用到節(jié)流和防抖了。
what?這是啥?當(dāng)我第一次聽(tīng)到這兩個(gè)名字的時(shí)候,心想是指節(jié)省流量、防止手抖嗎。百思不得其解,趕緊就去學(xué)習(xí)。
概念:
簡(jiǎn)單來(lái)說(shuō):節(jié)流和防抖就是為了防止事件在短時(shí)間內(nèi)多次觸發(fā)的兩種解決方案。都是用過(guò)減少請(qǐng)求的次數(shù),來(lái)降低壓力,提高性能。
區(qū)別
節(jié)流:在一定的時(shí)間內(nèi)只會(huì)請(qǐng)求一次。
可以理解為:公交車,每個(gè)人是一次點(diǎn)擊請(qǐng)求,每十分鐘開(kāi)一趟車,發(fā)送請(qǐng)求
防抖:觸發(fā)事件后n秒后才能執(zhí)行函數(shù),如果在n秒內(nèi)觸發(fā)了事件,則會(huì)重新計(jì)算執(zhí)行時(shí)間。
比如在一段時(shí)間內(nèi),我一直點(diǎn)擊按鈕,以最后一次點(diǎn)擊為準(zhǔn)發(fā)送一次請(qǐng)求。
節(jié)流實(shí)現(xiàn)
解決思路 :
使用時(shí)間戳(發(fā)生在一段時(shí)間的開(kāi)始),就是在計(jì)算
當(dāng)前點(diǎn)擊的時(shí)間 - 上一次執(zhí)行函數(shù)的時(shí)間 > 我設(shè)定的時(shí)間戳 ,就執(zhí)行一次函數(shù)
缺點(diǎn):第一次直接觸發(fā) 最后一次一段時(shí)間內(nèi)無(wú)法觸發(fā)
給一個(gè)場(chǎng)景,當(dāng)我們搜索數(shù)據(jù)的時(shí)候,發(fā)起請(qǐng)求,沒(méi)有做處理是這樣的,請(qǐng)求肯定太過(guò)于頻繁

節(jié)流函數(shù)
代碼:
<body>
<div>
<span>節(jié)流處理</span><input id="input" type="text">
<button id="btn">請(qǐng)求</button>
</div>
</body>
<script>
var btn = document.getElementById("btn")
btn.addEventListener("click", throttle(output, 1000)) //添加點(diǎn)擊事件監(jiān)聽(tīng)
function output(e) {
console.log(this, e)
console.log(document.getElementById("input").value) //模擬發(fā)起一次請(qǐng)求
}
//節(jié)流函數(shù)
function throttle(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
var last = 0; //上一次結(jié)束的時(shí)間
return function () {
var cur = Date.now()
console.log(cur-last)
if (cur - last > delay) {
fn.apply(this, arguments) //執(zhí)行函數(shù)
last = cur //更新上一次時(shí)間
}
}
}
</script>
效果:

防抖實(shí)現(xiàn)
解決思路 :
定時(shí)器(發(fā)生在定時(shí)結(jié)束)。缺點(diǎn):第一次不觸發(fā) 最后一次延遲觸發(fā)
就是設(shè)置一個(gè)定時(shí)器,如果一直點(diǎn)擊則清除定時(shí)器,最后一次開(kāi)啟定時(shí)器
防抖函數(shù)
代碼:
<body>
<div>
<span>防抖處理</span><input id="input" type="text">
<button id="btn">請(qǐng)求</button>
</div>
</body>
<script>
var btn = document.getElementById("btn")
btn.addEventListener("click", debounce(output, 1000)) //添加點(diǎn)擊事件監(jiān)聽(tīng)
function output(e) {
console.log(this, e)
console.log(document.getElementById("input").value) //模擬發(fā)起一次請(qǐng)求
}
function debounce(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
var time = null; //定時(shí)器
return function () {
clearTimeout(time); //清除定時(shí)器
let context = this; //獲取當(dāng)前button上下文 如果不指定,箭頭函數(shù)就會(huì)一直往外找到window
let args = arguments;
time = setTimeout(() => {
fn.apply(context, args);
}, delay);
}
}
</script>
效果:

防抖升級(jí)版
第一次觸發(fā)和最后一次延遲觸發(fā)
代碼:
function throttle(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
let time = null
let flag=true //標(biāo)識(shí)是不是第一次觸發(fā)
return function () {
clearTimeout(time)
if (flag) {
fn.apply(this, arguments)
flag=false
}
time = setTimeout(() => { //觸發(fā)定時(shí)器
fn.apply(this, arguments)
flag=true
}, delay)
}
}
效果:

總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
節(jié)流與防抖
背景:當(dāng)我們頻繁去請(qǐng)求資源、接口等其他的時(shí)候,就會(huì)造成操作Dom頻繁,接口壓力大等等,性能下降。比如我有時(shí)候會(huì)每次搜索會(huì)猛地敲回車,在網(wǎng)絡(luò)不很好的時(shí)候,點(diǎn)擊下一頁(yè)按鈕的時(shí)候也會(huì)一直點(diǎn),可能網(wǎng)絡(luò)不好也可能服務(wù)器性能低。
為了避免頻繁觸發(fā)同一事件或請(qǐng)求,這時(shí)候就要用到節(jié)流和防抖了。
what?這是啥?當(dāng)我第一次聽(tīng)到這兩個(gè)名字的時(shí)候,心想是指節(jié)省流量、防止手抖嗎。百思不得其解,趕緊就去學(xué)習(xí)。
概念:
簡(jiǎn)單來(lái)說(shuō):節(jié)流和防抖就是為了防止事件在短時(shí)間內(nèi)多次觸發(fā)的兩種解決方案。都是用過(guò)減少請(qǐng)求的次數(shù),來(lái)降低壓力,提高性能。
區(qū)別
節(jié)流:在一定的時(shí)間內(nèi)只會(huì)請(qǐng)求一次。
可以理解為:公交車,每個(gè)人是一次點(diǎn)擊請(qǐng)求,每十分鐘開(kāi)一趟車,發(fā)送請(qǐng)求
防抖:觸發(fā)事件后n秒后才能執(zhí)行函數(shù),如果在n秒內(nèi)觸發(fā)了事件,則會(huì)重新計(jì)算執(zhí)行時(shí)間。
比如在一段時(shí)間內(nèi),我一直點(diǎn)擊按鈕,以最后一次點(diǎn)擊為準(zhǔn)發(fā)送一次請(qǐng)求。
節(jié)流實(shí)現(xiàn)
解決思路 :
使用時(shí)間戳(發(fā)生在一段時(shí)間的開(kāi)始),就是在計(jì)算
當(dāng)前點(diǎn)擊的時(shí)間 - 上一次執(zhí)行函數(shù)的時(shí)間 > 我設(shè)定的時(shí)間戳 ,就執(zhí)行一次函數(shù)
缺點(diǎn):第一次直接觸發(fā) 最后一次一段時(shí)間內(nèi)無(wú)法觸發(fā)
給一個(gè)場(chǎng)景,當(dāng)我們搜索數(shù)據(jù)的時(shí)候,發(fā)起請(qǐng)求,沒(méi)有做處理是這樣的,請(qǐng)求肯定太過(guò)于頻繁

節(jié)流函數(shù)
代碼:
<body>
<div>
<span>節(jié)流處理</span><input id="input" type="text">
<button id="btn">請(qǐng)求</button>
</div>
</body>
<script>
var btn = document.getElementById("btn")
btn.addEventListener("click", throttle(output, 1000)) //添加點(diǎn)擊事件監(jiān)聽(tīng)
function output(e) {
console.log(this, e)
console.log(document.getElementById("input").value) //模擬發(fā)起一次請(qǐng)求
}
//節(jié)流函數(shù)
function throttle(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
var last = 0; //上一次結(jié)束的時(shí)間
return function () {
var cur = Date.now()
console.log(cur-last)
if (cur - last > delay) {
fn.apply(this, arguments) //執(zhí)行函數(shù)
last = cur //更新上一次時(shí)間
}
}
}
</script>
效果:

防抖實(shí)現(xiàn)
解決思路 :
定時(shí)器(發(fā)生在定時(shí)結(jié)束)。缺點(diǎn):第一次不觸發(fā) 最后一次延遲觸發(fā)
就是設(shè)置一個(gè)定時(shí)器,如果一直點(diǎn)擊則清除定時(shí)器,最后一次開(kāi)啟定時(shí)器
防抖函數(shù)
代碼:
<body>
<div>
<span>防抖處理</span><input id="input" type="text">
<button id="btn">請(qǐng)求</button>
</div>
</body>
<script>
var btn = document.getElementById("btn")
btn.addEventListener("click", debounce(output, 1000)) //添加點(diǎn)擊事件監(jiān)聽(tīng)
function output(e) {
console.log(this, e)
console.log(document.getElementById("input").value) //模擬發(fā)起一次請(qǐng)求
}
function debounce(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
var time = null; //定時(shí)器
return function () {
clearTimeout(time); //清除定時(shí)器
let context = this; //獲取當(dāng)前button上下文 如果不指定,箭頭函數(shù)就會(huì)一直往外找到window
let args = arguments;
time = setTimeout(() => {
fn.apply(context, args);
}, delay);
}
}
</script>
效果:

防抖升級(jí)版
第一次觸發(fā)和最后一次延遲觸發(fā)
代碼:
function throttle(fn, delay) { // fn為執(zhí)行的函數(shù),delay為延遲時(shí)間
let time = null
let flag=true //標(biāo)識(shí)是不是第一次觸發(fā)
return function () {
clearTimeout(time)
if (flag) {
fn.apply(this, arguments)
flag=false
}
time = setTimeout(() => { //觸發(fā)定時(shí)器
fn.apply(this, arguments)
flag=true
}, delay)
}
}
效果:

總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- JavaScript函數(shù)防抖動(dòng)debounce
- 通過(guò)實(shí)例講解JS如何防抖動(dòng)
- JavaScript運(yùn)動(dòng)框架 解決防抖動(dòng)問(wèn)題、懸浮對(duì)聯(lián)(二)
- JavaScript中防抖和節(jié)流的區(qū)別及適用場(chǎng)景
- JavaScript中防抖和節(jié)流的實(shí)戰(zhàn)應(yīng)用記錄
- JavaScript深入理解節(jié)流與防抖
- JavaScript防抖與節(jié)流的實(shí)現(xiàn)與注意事項(xiàng)
- JavaScript的防抖和節(jié)流一起來(lái)了解下
- JavaScript中函數(shù)的防抖與節(jié)流詳解
- javascript的防抖和節(jié)流你了解嗎
- 關(guān)于JavaScript防抖與節(jié)流的區(qū)別與實(shí)現(xiàn)
- JavaScript防抖與節(jié)流詳解
- JavaScript 防抖和節(jié)流詳解
- JavaScript防抖動(dòng)與節(jié)流處理
相關(guān)文章
javascript + jquery實(shí)現(xiàn)定時(shí)修改文章標(biāo)題
用javascript+jquery寫的一個(gè)定時(shí)器,定時(shí)修改文章標(biāo)題,需要的朋友可以參考下2014-03-03
javascript實(shí)現(xiàn)京東登錄顯示隱藏密碼
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)京東登錄顯示隱藏密碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
js獲取元素的外鏈樣式的簡(jiǎn)單實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇js獲取元素的外鏈樣式的簡(jiǎn)單實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
JS 實(shí)現(xiàn)banner圖片輪播效果(鼠標(biāo)事件)
js實(shí)現(xiàn)banner圖片輪播效果,通過(guò)鼠標(biāo)點(diǎn)擊左右可切換圖片,具體實(shí)現(xiàn)代碼大家參考下本文2017-08-08
JS設(shè)計(jì)模式之狀態(tài)模式的用法使用方法
JavaScript狀態(tài)模式是一種行為型設(shè)計(jì)模式,核心是對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變其行為,狀態(tài)模式將對(duì)象的行為封裝到不同的狀態(tài)類中,使得對(duì)象在不同狀態(tài)下可以選擇不同的行為,本文給大家詳細(xì)的介紹一下?tīng)顟B(tài)設(shè)計(jì)模式在Js中的使用,需要的朋友可以參考下2023-08-08
JavaScript使用promise處理多重復(fù)請(qǐng)求
處理重復(fù)請(qǐng)求的文章想必大家也看過(guò)了很多,大多數(shù)都是分為在response返回之前發(fā)現(xiàn)重復(fù)請(qǐng)求就return掉的和使用節(jié)流/防抖來(lái)間接規(guī)避用戶頻繁操作兩種版本的。本文主要介紹了JavaScript使用promise處理多重復(fù)請(qǐng)求,感興趣的可以了解一下2021-05-05

