如何理解JS函數(shù)防抖和函數(shù)節(jié)流
概述
函數(shù)防抖和函數(shù)節(jié)流都是定義一個(gè)函數(shù),該函數(shù)接收一個(gè)函數(shù)作為參數(shù),并返回一個(gè)添加了防抖或節(jié)流功能后的函數(shù)。
因此可以將函數(shù)防抖和函數(shù)節(jié)流看作是一個(gè)函數(shù)工廠,負(fù)責(zé)對(duì)傳進(jìn)來(lái)的函數(shù)進(jìn)行相應(yīng)的加工改造,然后產(chǎn)出一個(gè)新的帶有某種功能的函數(shù)。
函數(shù)防抖是某一時(shí)間內(nèi)只執(zhí)行一次,而函數(shù)節(jié)流是間隔時(shí)間執(zhí)行
假如有這樣一個(gè)場(chǎng)景:在某一頁(yè)面,有一個(gè)按鈕是 "加載更多",這個(gè)按鈕的作用就是使用 ajax 從后端服務(wù)器請(qǐng)求更多的數(shù)據(jù)展示在頁(yè)面,我們都知道,ajax 請(qǐng)求的響應(yīng)是一個(gè)異步的,會(huì)存在一定的響應(yīng)時(shí)間,如果用戶在點(diǎn)擊了該按鈕后,立馬又點(diǎn)擊了一下該按鈕,按照常規(guī)回調(diào)函數(shù)的操作,回調(diào)函數(shù)會(huì)立馬又執(zhí)行一次,那么就是用戶短時(shí)間內(nèi)點(diǎn)擊了兩次 "加載更多" 按鈕后就會(huì)執(zhí)行回調(diào)函數(shù)向后端發(fā)起了兩次一模一樣的 ajax 請(qǐng)求,服務(wù)器會(huì)一一接收請(qǐng)求并處理返回?cái)?shù)據(jù),短時(shí)間內(nèi)兩次請(qǐng)求還好,如果用戶連續(xù)點(diǎn)擊了 n 次 "加載更多" 按鈕呢?那就會(huì)短時(shí)間內(nèi)向服務(wù)器發(fā)送了 n 次一模一樣的請(qǐng)求,每次后端處理 ajax 請(qǐng)求后返回?cái)?shù)據(jù)后頁(yè)面就會(huì)重新再渲染一次,盡管內(nèi)容沒(méi)有改變,這樣就會(huì)帶來(lái)性能上的問(wèn)題,不僅為服務(wù)器帶去了壓力,也為瀏覽器帶來(lái)了不必要的渲染,這就是函數(shù)頻繁執(zhí)行帶來(lái)的副作用。
那么如何設(shè)置這個(gè)按鈕的點(diǎn)擊事件回調(diào)函數(shù)才能減少該函數(shù)頻繁執(zhí)行帶來(lái)的副作用呢?
1. 函數(shù)防抖(debounce)
函數(shù)防抖的設(shè)計(jì)思路就是在函數(shù)執(zhí)行前加一個(gè)等待時(shí)間,在這個(gè)等待時(shí)間內(nèi)如果該函數(shù)又需要執(zhí)行一次,就重新計(jì)算等待時(shí)間,再次等待,依次類推,直到等待時(shí)間到了,還沒(méi)有等到函數(shù)又需要執(zhí)行的情況,才會(huì)執(zhí)行這個(gè)函數(shù)。
就拿上述的場(chǎng)景來(lái)說(shuō),假設(shè)向后臺(tái)發(fā)送 ajax 請(qǐng)求的響應(yīng)時(shí)間大概是在 2s 左右,那就設(shè)置這個(gè)等待時(shí)間為 2s,當(dāng)用戶第一次點(diǎn)擊"加載更多"按鈕后,該回調(diào)函數(shù)并沒(méi)有立即執(zhí)行,也就是還沒(méi)有開(kāi)始發(fā)送 ajax,此時(shí)該函數(shù)在等待,如果在 2s 內(nèi)用戶又點(diǎn)擊了"加載更多",那就重新計(jì)算等待時(shí)間,再等待 2s ,此時(shí) 2s 過(guò)去了,用戶沒(méi)再第三次點(diǎn)擊"加載更多"按鈕了,那么該函數(shù)就開(kāi)始執(zhí)行了,向后端發(fā)送 ajax 請(qǐng)求了。
函數(shù)防抖實(shí)現(xiàn)方式如下:
function debounce(fn, delay){
let timeId = null
return function(){
let context = this
if(timeId){window.clearTimeout(timeId)}
timeId = setTimeout(()=>{
fn.apply(context, arguments)
timeId = null
},delay)
}
}
2. 函數(shù)節(jié)流(throttle)
函數(shù)節(jié)流的設(shè)計(jì)思路是在函數(shù)執(zhí)行后加一個(gè)冷卻時(shí)間,函數(shù)在第一次執(zhí)行時(shí)是立馬執(zhí)行,但在其執(zhí)行完后設(shè)置一個(gè)冷卻時(shí)間,在冷卻時(shí)間內(nèi),該函數(shù)不能再次執(zhí)行,直到冷卻時(shí)間結(jié)束允許該函數(shù)執(zhí)行了,才可以再次執(zhí)行。
就拿上述的場(chǎng)景來(lái)說(shuō),冷卻時(shí)間假設(shè)也設(shè)置為 2s,在用戶第一次點(diǎn)擊"加載更多" 后按鈕的回調(diào)函數(shù)就會(huì)執(zhí)行,也就是會(huì)向后臺(tái)發(fā)送 ajax 請(qǐng)求,此時(shí)用戶又立馬再次點(diǎn)擊了"加載更多"按鈕,由于此刻 2s 的冷卻時(shí)間還沒(méi)有到,那么就會(huì)給第二次的函數(shù)執(zhí)行加上一個(gè)延遲執(zhí)行。
function throttle(fn, delay){
let canUse = true
return function(){
if(canUse){
fn.apply(this, arguments)
canUse = false
setTimeout(()=>canUse=true, delay)
}
}
}
以上就是如何理解JS函數(shù)防抖和函數(shù)節(jié)流的詳細(xì)內(nèi)容,更多關(guān)于JS函數(shù)防抖和函數(shù)節(jié)流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript數(shù)字?jǐn)?shù)組去重復(fù)項(xiàng)的實(shí)現(xiàn)代碼
console.log 不支持ie,下面的代碼需要在火狐中測(cè)試,不然會(huì)有問(wèn)題。2010-12-12
JavaScript語(yǔ)法高亮插件highlight.js用法詳解【附highlight.js本站下載】
這篇文章主要介紹了JavaScript語(yǔ)法高亮庫(kù)highlight.js用法,詳細(xì)分析了highlight.js的下載、調(diào)用及具體使用技巧,需要的朋友可以參考下2016-11-11
JavaScript事件學(xué)習(xí)小結(jié)(三)js事件對(duì)象
這篇文章主要介紹了JavaScript事件學(xué)習(xí)小結(jié)(三)js事件對(duì)象的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
使用D3.js構(gòu)建實(shí)時(shí)圖形的示例代碼
這篇文章主要介紹了使用D3.js構(gòu)建實(shí)時(shí)圖形的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
基于Bootstrap的標(biāo)簽頁(yè)組件及bootstrap-tab使用說(shuō)明
這篇文章主要介紹了基于Bootstrap的標(biāo)簽頁(yè)組件及bootstrap-tab使用說(shuō)明,需要的朋友可以參考下2017-07-07
javascript基于原型鏈的繼承及call和apply函數(shù)用法分析
這篇文章主要介紹了javascript基于原型鏈的繼承及call和apply函數(shù)用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了javascript中繼承的概念、創(chuàng)建方法以及call和apply函數(shù)的功能與使用技巧,需要的朋友可以參考下2016-12-12
基于JavaScript實(shí)現(xiàn)TAB標(biāo)簽效果
js實(shí)現(xiàn)tab標(biāo)簽效果,在項(xiàng)目中經(jīng)常用到,今天抽點(diǎn)時(shí)間把我寫的js實(shí)現(xiàn)tab標(biāo)簽效果源碼分享給大家,對(duì)js tab標(biāo)簽代碼需要的朋友參考下2016-01-01
javascript瀑布流式圖片懶加載實(shí)例解析與優(yōu)化
這篇文章主要針對(duì)javascript瀑布流式圖片懶加載實(shí)例進(jìn)行解析與優(yōu)化,感興趣的小伙伴們可以參考一下2016-02-02

