詳解JS函數(shù)防抖
一、什么是函數(shù)防抖
概念:函數(shù)防抖(debounce),就是指觸發(fā)事件后,在 n 秒內(nèi)函數(shù)只能執(zhí)行一次,如果觸發(fā)事件后在 n 秒內(nèi)又觸發(fā)了事件,則會重新計(jì)算函數(shù)延執(zhí)行時(shí)間。
舉個(gè)栗子,坐電梯的時(shí)候,如果電梯檢測到有人進(jìn)來(觸發(fā)事件),就會多等待 10 秒,此時(shí)如果又有人進(jìn)來(10秒之內(nèi)重復(fù)觸發(fā)事件),那么電梯就會再多等待 10 秒。在上述例子中,電梯在檢測到有人進(jìn)入 10 秒鐘之后,才會關(guān)閉電梯門開始運(yùn)行,因此,“函數(shù)防抖”的關(guān)鍵在于,在 一個(gè)事件 發(fā)生 一定時(shí)間 之后,才執(zhí)行 特定動作。
二、為什么需要函數(shù)防抖
前端開發(fā)過程中,有一些事件,常見的例如,onresize,scroll,mousemove ,mousehover
等,會被頻繁觸發(fā)(短時(shí)間內(nèi)多次觸發(fā)),不做限制的話,有可能一秒之內(nèi)執(zhí)行幾十次、幾百次,如果在這些函數(shù)內(nèi)部執(zhí)行了其他函數(shù),尤其是執(zhí)行了操作 DOM 的函數(shù)(瀏覽器操作 DOM 是很耗費(fèi)性能的),那不僅會浪費(fèi)計(jì)算機(jī)資源,還會降低程序運(yùn)行速度,甚至造成瀏覽器卡死、崩潰。這種問題顯然是致命的。
除此之外,短時(shí)間內(nèi)重復(fù)的 ajax 調(diào)用不僅會造成數(shù)據(jù)關(guān)系的混亂,還會造成網(wǎng)絡(luò)擁塞,增加服務(wù)器壓力,顯然這個(gè)問題也是需要解決的。
三、函數(shù)防抖如何解決上述問題
根據(jù)上面對問題的分析,細(xì)細(xì)思索,可以想到如下解決方案。
函數(shù)防抖的要點(diǎn),是需要一個(gè) setTimeout
來輔助實(shí)現(xiàn),延遲運(yùn)行需要執(zhí)行的代碼。如果方法多次觸發(fā),則把上次記錄的延遲執(zhí)行代碼用 clearTimeout
清掉,重新開始計(jì)時(shí)。若計(jì)時(shí)期間事件沒有被重新觸發(fā),等延遲時(shí)間計(jì)時(shí)完畢,則執(zhí)行目標(biāo)代碼。
四、函數(shù)防抖的代碼實(shí)現(xiàn)
根據(jù)以上分析,我們對 “函數(shù)防抖” 來進(jìn)行簡單的代碼實(shí)現(xiàn),如下:
function debounce(fn,wait){ var timer = null; return function(){ if(timer !== null){ clearTimeout(timer); } timer = setTimeout(fn,wait); } } function handle(){ console.log(Math.random()); } window.addEventListener("resize",debounce(handle,1000));
五、函數(shù)節(jié)流的使用場景
函數(shù)防抖一般用在什么情況之下呢?一般用在,連續(xù)的事件只需觸發(fā)一次回調(diào)的場合。具體有:
搜索框搜索輸入。只需用戶最后一次輸入完,再發(fā)送請求;
用戶名、手機(jī)號、郵箱輸入驗(yàn)證;
瀏覽器窗口大小改變后,只需窗口調(diào)整完后,再執(zhí)行 resize
事件中的代碼,防止重復(fù)渲染。
目前遇到過的用處就是這些,理解了原理與實(shí)現(xiàn)思路,小伙伴可以把它運(yùn)用在任何需要的場合,提高代碼質(zhì)量。
總結(jié)
函數(shù)防抖其實(shí)是分為 “立即執(zhí)行版” 和 “非立即執(zhí)行版” 的,根據(jù)字面意思就可以發(fā)現(xiàn)他們的差別,所謂立即執(zhí)行版就是 觸發(fā)事件后函數(shù)不會立即執(zhí)行,而是在 n 秒后執(zhí)行,如果在 n 秒內(nèi)又觸發(fā)了事件,則會重新計(jì)算函數(shù)執(zhí)行時(shí)間。 而 “非立即執(zhí)行版” 指的是 觸發(fā)事件后函數(shù)會立即執(zhí)行,然后 n 秒內(nèi)不觸發(fā)事件才能繼續(xù)執(zhí)行函數(shù)的效果。。
在開發(fā)過程中,我們需要根據(jù)不同的場景來決定我們需要使用哪一個(gè)版本的防抖函數(shù),一般來講上述的防抖函數(shù)都能滿足大部分的場景需求。但我們也可以將非立即執(zhí)行版和立即執(zhí)行版的防抖函數(shù)結(jié)合起來,實(shí)現(xiàn)最終的雙劍合璧版本的防抖函數(shù),以下為小伙伴們做了簡單的實(shí)現(xiàn):
/** * @desc 函數(shù)防抖---“立即執(zhí)行版本” 和 “非立即執(zhí)行版本” 的組合版本 * @param func 需要執(zhí)行的函數(shù) * @param wait 延遲執(zhí)行時(shí)間(毫秒) * @param immediate---true 表立即執(zhí)行,false 表非立即執(zhí)行 **/ function debounce(func,wait,immediate) { let timer; return function () { let context = this; let args = arguments; if (timer) clearTimeout(timer); if (immediate) { var callNow = !timer; timer = setTimeout(() => { timer = null; }, wait) if (callNow) func.apply(context, args) } else { timer = setTimeout(function(){ func.apply(context, args) }, wait); } } } function handle(){ console.log(Math.random()); } // window.addEventListener("mousemove",debounce(handle,1000,true)); // 調(diào)用立即執(zhí)行版本 window.addEventListener("mousemove",debounce(handle,1000,false)); // 調(diào)用非立即執(zhí)行版本
以上就是詳解JS函數(shù)防抖的詳細(xì)內(nèi)容,更多關(guān)于JS函數(shù)防抖的資料請關(guān)注腳本之家其它相關(guān)文章!
- JS函數(shù)節(jié)流和函數(shù)防抖問題分析
- JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別
- 淺析JavaScript 函數(shù)防抖和節(jié)流
- 如何解決js函數(shù)防抖、節(jié)流出現(xiàn)的問題
- JavaScript性能優(yōu)化之函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce)
- JavaScript函數(shù)節(jié)流概念與用法實(shí)例詳解
- JS中setTimeout的巧妙用法前端函數(shù)節(jié)流
- 淺談JavaScript函數(shù)節(jié)流
- 如何理解JS函數(shù)防抖和函數(shù)節(jié)流
相關(guān)文章
Javascript 入門基礎(chǔ)學(xué)習(xí)
習(xí).net已經(jīng)近2年了,最近學(xué)習(xí)Ajax時(shí)發(fā)現(xiàn)自己的很多技術(shù)功底很是欠缺,比如JavaScript。今后我會將我正在學(xué)習(xí)的也寫成筆記,有時(shí)間的話將以前的東西整理整理也傳上來。2010-03-03表單元素的submit()方法和onsubmit事件應(yīng)用概述
表單元素?fù)碛衧ubmit方法,同時(shí)也具有onsubmit事件句柄,用于監(jiān)聽表單提交??梢允褂胑lemForm.submit();方法觸發(fā)表單提交,感興趣的朋友可以了解下,或許對你有所幫助2013-02-02javascript中對Date類型的常用操作小結(jié)
下面小編就為大家?guī)硪黄猨avascript中對Date類型的常用操作小結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-05-05Javascript排序算法之合并排序(歸并排序)的2個(gè)例子
這篇文章主要介紹了Javascript排序算法之合并排序(歸并排序)的2個(gè)例子,需要的朋友可以參考下2014-04-04