如何理解JS事件的防抖與節(jié)流?
本文轉(zhuǎn)載自微信公眾號(hào)「新鈦云服」,作者方章和。轉(zhuǎn)載本文請(qǐng)聯(lián)系新鈦云服公眾號(hào)。
在平時(shí)的編碼過(guò)程中,當(dāng)紿瀏覽器注冊(cè)一個(gè)時(shí)間,經(jīng)常會(huì)遇到一些執(zhí)行次數(shù)非常頻繁的事件,如scroll,resize等,事件頻繁的執(zhí)行會(huì)導(dǎo)致瀏覽器進(jìn)行大量的計(jì)算而引發(fā)頁(yè)面卡頓假死的情況,為些我們需要通過(guò)一些手段來(lái)解決這個(gè)問(wèn)題,所以就有了防抖和節(jié)流這兩個(gè)技術(shù)。
事件節(jié)流 throttle
是指在某段時(shí)間內(nèi),不管你觸發(fā)了多少次回調(diào)事件,我都只認(rèn)第一次,并在計(jì)時(shí)結(jié)束時(shí)給予響應(yīng),至于后面你再觸發(fā)多少次回調(diào)我都不會(huì)予以回應(yīng)。代碼實(shí)現(xiàn)如下:
- // fn執(zhí)行的函數(shù), interval是時(shí)間間隔的閾值, 意為多久后執(zhí)行,單位毫秒
- function throttle(fn, interval) {
- // 上一次觸發(fā)回調(diào)的時(shí)間
- let last = 0
- return function () {
- let context = this
- let args = arguments
- let now = +new Date()
- // 判斷上次觸發(fā)的時(shí)間和本次觸發(fā)的時(shí)間差是否小于設(shè)置的間隔時(shí)間
- if (now - last >= interval) {
- // 如果時(shí)間間隔大于我們?cè)O(shè)定的時(shí)間間隔閾值,則執(zhí)行回調(diào)
- last = now;
- fn.apply(context, args);
- }
- }
- }
- // 紿scroll事件增加節(jié)流
- const newScroll = throttle(() => console.log('滾動(dòng)了'), 1000)
- document.addEventListener('scroll', newScroll)
事件防抖Debounce
與事件節(jié)流怡好相反,事件防抖只認(rèn)最后一次,不管你前面觸發(fā)了多少次我都不管,我只執(zhí)行你最后一次觸發(fā)事件的回調(diào),代碼實(shí)現(xiàn)如下:
- // fn執(zhí)行的函數(shù), delay是延遲多久執(zhí)行的時(shí)間, 意為多久后才觸發(fā)事件,單位毫秒
- function debounce(fn, delay) {
- let timer = null
- return function () {
- let context = this
- let args = arguments
- // 每次事件被觸發(fā)時(shí),都去清除之前的舊定時(shí)器
- if(timer) {
- clearTimeout(timer)
- }
- timer = setTimeout(function () {
- fn.apply(context, args)
- }, delay)
- }
- }
- const newScroll = debounce(() => console.log('滾動(dòng)了'), 1000)
- document.addEventListener('scroll', newScroll)
函數(shù)防抖的應(yīng)用場(chǎng)景
連續(xù)的事件,只需觸發(fā)一次回調(diào)的場(chǎng)景有:
搜索框搜索輸入。只需用戶(hù)最后一次輸入完,再發(fā)送請(qǐng)求
手機(jī)號(hào)、郵箱驗(yàn)證輸入檢測(cè)
窗口大小Resize。只需窗口調(diào)整完成后,計(jì)算窗口大小。防止重復(fù)渲染。
函數(shù)節(jié)流的應(yīng)用場(chǎng)景
間隔一段時(shí)間執(zhí)行一次回調(diào)的場(chǎng)景有:
- 滾動(dòng)加載,加載更多或滾到底部監(jiān)聽(tīng)
- 百度搜索框,搜索聯(lián)想功能
- 高頻點(diǎn)擊提交,表單重復(fù)提交