欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文學(xué)會(huì)JavaScript如何手寫防抖節(jié)流

 更新時(shí)間:2022年11月30日 10:25:08   作者:大眼睛圖圖  
其實(shí)防抖和節(jié)流不僅僅在面試中會(huì)讓大家手寫,在實(shí)際項(xiàng)目中也可以起到性能優(yōu)化的作用,所以還是很有必要掌握的。這篇文章就帶大家徹底學(xué)會(huì)JavaScript手寫防抖節(jié)流,希望對(duì)大家有所幫助

前言

記得當(dāng)初看這篇大佬的文章一杯茶的時(shí)間,帶你徹底學(xué)會(huì)手寫防抖節(jié)流已經(jīng)對(duì)防抖節(jié)流有了個(gè)清晰的認(rèn)識(shí),但那個(gè)時(shí)候由于真的是第一次接觸到防抖節(jié)流,對(duì)它的手寫方式還是很迷,卡在著卡了很久。

所以今天打算在那篇文章的基礎(chǔ)上做一些補(bǔ)充,讓小白對(duì)防抖節(jié)流的手寫能夠真正掌握。

防抖節(jié)流的概念

  • 防抖: n 秒后在執(zhí)行該事件,若在 n 秒內(nèi)被重復(fù)觸發(fā),則重新計(jì)時(shí)
  • 節(jié)流: n 秒內(nèi)只運(yùn)行一次,若在 n 秒內(nèi)重復(fù)觸發(fā),只有一次生效

一個(gè)經(jīng)典的比喻:

想象每天上班大廈底下的電梯。把電梯完成一次運(yùn)送,類比為一次函數(shù)的執(zhí)行和響應(yīng)

假設(shè)電梯有兩種運(yùn)行策略 debounce 和 throttle,超時(shí)設(shè)定為15秒,不考慮容量限制

電梯第一個(gè)人進(jìn)來后,等待15秒。如果過程中又有人進(jìn)來,15秒等待重新計(jì)時(shí),直到15秒后開始運(yùn)送,這是防抖。

電梯第一個(gè)人進(jìn)來后,15秒后準(zhǔn)時(shí)運(yùn)送一次,這是節(jié)流。

再舉個(gè)不太嚴(yán)謹(jǐn)?shù)谋扔鳎?/p>

防抖:就是王者榮耀里的回城,一段時(shí)間內(nèi)被打斷,就又要重新計(jì)時(shí)。

節(jié)流:就是王者榮耀里英雄的技能,像東皇的大一般都是20s準(zhǔn)時(shí)來一次。

手寫

防抖

首先我們先簡(jiǎn)單的模擬一個(gè)按鈕被點(diǎn)擊的過程。

let addBtn=document.getElementById('add')
function addOne(){
  console.log('增加一個(gè)')
}
addBtn.addEventListener('click',addOne)

加入防抖功能

// debounce.js
let addBtn=document.getElementById('add')

function addOne(){
  console.log('增加一個(gè)')
}

function debounce(fun,time){
    setTimeout(()=>{
      fun()
    },time)
}
addBtn.addEventListener('click',debounce(addOne,2000))

現(xiàn)在延時(shí)的目的是達(dá)到了但是每次點(diǎn)擊都會(huì)新增一個(gè)新的setTimeout而且并不能達(dá)到我們多次點(diǎn)擊只執(zhí)行一次的效果。

這時(shí)候就需要clearTimeout登場(chǎng)了,我們需要在我們點(diǎn)擊了按鈕后也就是debounce執(zhí)行時(shí)要先把之前的setTimeout先清除再重新計(jì)時(shí)。

這時(shí)我們會(huì)很自然地想到這個(gè)寫法:

function debounce(fun, time) {
    let timer;
    
     // 如果之前就存在定時(shí)器,就要把之前那個(gè)定時(shí)器刪除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun()
        }, time)
    
}

但是這樣寫的話拿的到之前定時(shí)器的值嗎?

當(dāng)然是拿不到的,因?yàn)槊看味紩?huì)重新let timer,所以這個(gè)時(shí)候我們就要使用閉包(延遲了變量的生命周期)了。

如果你還不太理解閉包,可以參考這篇文章包教包會(huì)——作用域鏈+閉包

引入閉包后

function addOne(){
  console.log('增加一個(gè)')
}

function debounce(fun, time) {
    let timer;
    
    return function(){
     // 如果之前就存在定時(shí)器,就要把之前那個(gè)定時(shí)器刪除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun()
        }, time)
        
    }
}

addBtn.addEventListener('click',debounce(addOne,2000))

這里還有一點(diǎn)需要知道的,每執(zhí)行一次addEventListener,debounce因?yàn)榉祷氐氖且粋€(gè)函數(shù),并結(jié)合addEventListener的特點(diǎn),會(huì)直接執(zhí)行debounce返回的函數(shù),不會(huì)出現(xiàn)每次都let timer

  • 現(xiàn)在我們的一個(gè)防抖功能就完成了,但是這還沒完,如果我們?cè)?code>addOne()打印this會(huì)發(fā)現(xiàn)我們這樣執(zhí)行的this是指向Window的。
  • 這當(dāng)然不是我們所希望的,我們需要使用apply來改變this指向,再者就是我們需要考慮到執(zhí)行函數(shù)的參數(shù),因?yàn)椴煌暮瘮?shù)肯定會(huì)有不同的參數(shù)傳入,對(duì)于參數(shù)我們可以使用arguments處理。
function debounce(fun, time) {
    let timer;
    
    return function(){
     // 如果之前就存在定時(shí)器,就要把之前那個(gè)定時(shí)器刪除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun.apply(this, arguments)
        }, time)
        
    }
}

這樣一個(gè)防抖就寫出來了

節(jié)流

  • 首先我們先模擬一個(gè)觸發(fā)事件。
  • 接下來我們封裝一個(gè)節(jié)流函數(shù),跟防抖一樣我們也需要利用閉包,順便再加一個(gè)參數(shù)接收節(jié)流時(shí)間。
// throttle.js
function scrollTest(){ 
    console.log('現(xiàn)在我觸發(fā)了')
}

function throttle(fun,time){
  return function(){
    fun()
  }
}
document.addEventListener('scroll',throttle(scrollTest,3000))

這里用閉包是為了后面獲得上一次的時(shí)間

  • 因?yàn)槲覀兊墓?jié)流是在一段時(shí)間內(nèi)執(zhí)行一次也就是說如果兩次鼠標(biāo)滾動(dòng)的時(shí)間間隔未到所設(shè)置的時(shí)間則不執(zhí)行
  • 那我們可以記錄一下每次滾動(dòng)的時(shí)間戳來進(jìn)行對(duì)比。
  • 當(dāng)然我們也需要像防抖一樣改變this指向和接收參數(shù),最后完成后是這樣的。
// throttle.js
...
function throttle(fun,time){
  let t1=0 //初始時(shí)間
  return function(){
    let t2=new Date() //當(dāng)前時(shí)間
    if(t2-t1>time){
      fun.apply(this,arguments)
      t1=t2
    }
  }
}

應(yīng)用場(chǎng)景

防抖在連續(xù)的事件,只需觸發(fā)一次回調(diào)的場(chǎng)景有:

  • 搜索框搜索輸入。只需用戶最后一次輸入完,再發(fā)送請(qǐng)求
  • 手機(jī)號(hào)、郵箱驗(yàn)證輸入檢測(cè)
  • 窗口大小resize。只需窗口調(diào)整完成后,計(jì)算窗口大小。防止重復(fù)渲染。

節(jié)流在間隔一段時(shí)間執(zhí)行一次回調(diào)的場(chǎng)景有:

  • 滾動(dòng)加載,加載更多或滾到底部監(jiān)聽
  • 搜索框,搜索聯(lián)想功能

到此這篇關(guān)于一文學(xué)會(huì)JavaScript如何手寫防抖節(jié)流的文章就介紹到這了,更多相關(guān)JavaScript防抖節(jié)流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論