成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

函數(shù)的防抖和節(jié)流是個(gè)啥???

edagarli / 1931人閱讀

摘要:函數(shù)防抖和節(jié)流,都是控制事件觸發(fā)頻率的方法。封裝一個(gè)函數(shù),讓持續(xù)觸發(fā)的事件監(jiān)聽(tīng)是我們封裝的這個(gè)函數(shù),將目標(biāo)函數(shù)作為回調(diào)傳進(jìn)去,等待一段時(shí)間過(guò)后執(zhí)行目標(biāo)函數(shù)第二點(diǎn)實(shí)現(xiàn)了,再看第一點(diǎn)持續(xù)觸發(fā)不執(zhí)行。

曾經(jīng)面試時(shí)候被問(wèn)到過(guò)這個(gè),年少的我一臉無(wú)知。。。

后來(lái)工作中遇到了一個(gè)場(chǎng)景:輸入名稱(chēng)的同時(shí)去服務(wù)器校驗(yàn)名稱(chēng)是否重復(fù),但發(fā)現(xiàn)之前的代碼竟然都沒(méi)做限制,輸入一次發(fā)一次請(qǐng)求。簡(jiǎn)直忍不了,就在項(xiàng)目的utils里加上了防抖函數(shù)。
正好做一個(gè)總結(jié),加深印象。

函數(shù)防抖和節(jié)流,都是控制事件觸發(fā)頻率的方法。應(yīng)用場(chǎng)景有很多,輸入框持續(xù)輸入,將輸入內(nèi)容遠(yuǎn)程校驗(yàn)、多次觸發(fā)點(diǎn)擊事件、onScroll等等。
為了說(shuō)明問(wèn)題,假設(shè)一個(gè)場(chǎng)景:鼠標(biāo)滑過(guò)一個(gè)div,觸發(fā)onmousemove事件,它內(nèi)部的文字會(huì)顯示當(dāng)前鼠標(biāo)的坐標(biāo)。



效果是這樣的:

在上邊的場(chǎng)景下,我們不希望觸發(fā)一次就執(zhí)行一次,這就要用到防抖或節(jié)流。下面我們看一下它們能為我們做什么吧。

防抖

函數(shù)防抖,這里的抖動(dòng)就是執(zhí)行的意思,而一般的抖動(dòng)都是持續(xù)的,多次的。假設(shè)函數(shù)持續(xù)多次執(zhí)行,
我們希望讓它冷靜下來(lái)再執(zhí)行。也就是當(dāng)持續(xù)觸發(fā)事件的時(shí)候,函數(shù)是完全不執(zhí)行的,等最后一次觸發(fā)結(jié)束的
一段時(shí)間之后,再去執(zhí)行。先看一下效果:

分解一下需求:

持續(xù)觸發(fā)不執(zhí)行

不觸發(fā)的一段時(shí)間之后再執(zhí)行

那么怎么實(shí)現(xiàn)上述的目標(biāo)呢?我們先看這一點(diǎn):在不觸發(fā)的一段時(shí)間之后再執(zhí)行,那就需要個(gè)定時(shí)器呀,定時(shí)器里面調(diào)用我們要執(zhí)行的函數(shù),將arguments傳入。
封裝一個(gè)函數(shù),讓持續(xù)觸發(fā)的事件監(jiān)聽(tīng)是我們封裝的這個(gè)函數(shù),將目標(biāo)函數(shù)作為回調(diào)(func)傳進(jìn)去,等待一段時(shí)間過(guò)后執(zhí)行目標(biāo)函數(shù)

function debounce(func, delay) {
  return function() {
    setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}

第二點(diǎn)實(shí)現(xiàn)了,再看第一點(diǎn):持續(xù)觸發(fā)不執(zhí)行。我們先思考一下,是什么讓我們的函數(shù)執(zhí)行了呢?是上邊的setTimeout。OK,那現(xiàn)在的問(wèn)題就變成了
持續(xù)觸發(fā),不能有setTimeout。這樣直接在事件持續(xù)觸發(fā)的時(shí)候,清掉定時(shí)器就好了。

function debounce(func, delay) {
  let timeout
  return function() {
    clearTimeout(timeout) // 如果持續(xù)觸發(fā),那么就清除定時(shí)器,定時(shí)器的回調(diào)就不會(huì)執(zhí)行。
    timeout = setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}

用法:

  box.onmousemove = debounce(function (e) {
    box.innerHTML = `${e.clientX}, ${e.clientY}`
  }, 1000)
節(jié)流

節(jié)流的意思是讓函數(shù)有節(jié)制地執(zhí)行,而不是毫無(wú)節(jié)制的觸發(fā)一次就執(zhí)行一次。什么叫有節(jié)制呢?就是在一段時(shí)間內(nèi),只執(zhí)行一次。
同樣,我們分解一下:

持續(xù)觸發(fā)并不會(huì)執(zhí)行多次

到一定時(shí)間再去執(zhí)行

效果是這樣的:

思考一下,持續(xù)觸發(fā),并不會(huì)執(zhí)行,但是到時(shí)間了就會(huì)執(zhí)行。抓取一個(gè)關(guān)鍵的點(diǎn):就是執(zhí)行的時(shí)機(jī)。
要做到控制執(zhí)行的時(shí)機(jī),我們可以通過(guò)一個(gè)開(kāi)關(guān),與定時(shí)器setTimeout結(jié)合完成。

函數(shù)執(zhí)行的前提條件是開(kāi)關(guān)打開(kāi),持續(xù)觸發(fā)時(shí),持續(xù)關(guān)閉開(kāi)關(guān),等到setTimeout到時(shí)間了,再把開(kāi)關(guān)打開(kāi),函數(shù)就會(huì)執(zhí)行了。
我們看一下代碼怎么實(shí)現(xiàn):

  function throttle(func, deley) {
    let run = true
    return function () {
      if (!run) {
        return  // 如果開(kāi)關(guān)關(guān)閉了,那就直接不執(zhí)行下邊的代碼
      }
      run = false // 持續(xù)觸發(fā)的話,run一直是false,就會(huì)停在上邊的判斷那里
      setTimeout(() => {
        func.apply(this, arguments)
        run = true // 定時(shí)器到時(shí)間之后,會(huì)把開(kāi)關(guān)打開(kāi),我們的函數(shù)就會(huì)被執(zhí)行
      }, deley)
    }
  }

調(diào)用的時(shí)候:

box.onmousemove = throttle(function (e) {
  box.innerHTML = `${e.clientX}, ${e.clientY}`
}, 1000)

這樣,就實(shí)現(xiàn)了節(jié)流,節(jié)流還可以用時(shí)間間隔去控制,就是記錄上一次函數(shù)的執(zhí)行時(shí)間,與當(dāng)前時(shí)間作比較,如果當(dāng)前時(shí)間與上次執(zhí)行時(shí)間的時(shí)間差大于一個(gè)值,就執(zhí)行。

說(shuō)明一下節(jié)流時(shí),后面操作中應(yīng)該是因?yàn)閞un=false 所以才直接return,但是不是在return之前l(fā)et run=ture直接覆蓋掉之前的false

這里可以看一下throttle函數(shù)內(nèi)部,和函數(shù)調(diào)用的時(shí)候。首先看函數(shù)內(nèi)部,分解一下結(jié)構(gòu):

function throttle(func, deley) {
    return function () {
      // 執(zhí)行func
    }
}

那調(diào)用時(shí)候呢?也分解一下:

throttle(function () { // 目標(biāo)函數(shù)內(nèi)容 }, 1000)

這里throttle函數(shù)執(zhí)行的結(jié)果是其內(nèi)部return的function的調(diào)用。也就是說(shuō)鼠標(biāo)經(jīng)過(guò)的事件監(jiān)聽(tīng)實(shí)際上是這個(gè)被return的function,不斷持續(xù)觸發(fā)的是它,而throttle函數(shù)只是提供了一個(gè)作用域,內(nèi)部用閉包聲明了一個(gè)run的開(kāi)關(guān)變量,由于閉包的存在,run這個(gè)變量會(huì)一直存在不被銷(xiāo)毀,而let run = true只在這個(gè)閉包(可以理解為作用域)內(nèi)只聲明了一次,但它不會(huì)被持續(xù)執(zhí)行,所以return的函數(shù)內(nèi)部的判斷不會(huì)被它覆蓋掉。根據(jù)打印結(jié)果可以看出,事實(shí)確實(shí)是如此:

總結(jié)

防抖和節(jié)流巧妙地用了setTimeout,來(lái)控制函數(shù)執(zhí)行的時(shí)機(jī),優(yōu)點(diǎn)很明顯,可以節(jié)約性能,不至于多次觸發(fā)復(fù)雜的業(yè)務(wù)邏輯而造成頁(yè)面卡頓。

歡迎關(guān)注我的公眾號(hào): 一口一個(gè)前端,不定期分享我所理解的前端知識(shí)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105490.html

相關(guān)文章

  • 從lodash源碼學(xué)習(xí)節(jié)流防抖

    摘要:首先重置防抖函數(shù)最后調(diào)用時(shí)間,然后去觸發(fā)一個(gè)定時(shí)器,保證后接下來(lái)的執(zhí)行。這就避免了手動(dòng)管理定時(shí)器。 ??之前遇到過(guò)一個(gè)場(chǎng)景,頁(yè)面上有幾個(gè)d3.js繪制的圖形。如果調(diào)整瀏覽器可視區(qū)大小,會(huì)引發(fā)圖形重繪。當(dāng)圖中的節(jié)點(diǎn)比較多的時(shí)候,頁(yè)面會(huì)顯得異??D。為了限制類(lèi)似于這種短時(shí)間內(nèi)高頻率觸發(fā)的情況,我們可以使用防抖函數(shù)。 ??實(shí)際開(kāi)發(fā)過(guò)程中,這樣的情況其實(shí)很多,比如: 頁(yè)面的scroll事件 ...

    CloudDeveloper 評(píng)論0 收藏0
  • 函數(shù)的防抖和節(jié)流

    摘要:當(dāng)持續(xù)觸發(fā)事件的時(shí)候,函數(shù)是完全不執(zhí)行的,等最后一次觸發(fā)結(jié)束的一段時(shí)間之后,再去執(zhí)行原理第一次調(diào)用函數(shù)創(chuàng)建一個(gè)定時(shí)器,指定的時(shí)間間隔后運(yùn)行代碼。第二次調(diào)用函數(shù)時(shí),它會(huì)清除前一次的定時(shí)器并設(shè)置另一個(gè)。 目的:節(jié)約性能開(kāi)銷(xiāo),避免多次頻繁的觸發(fā)業(yè)務(wù)邏輯造成頁(yè)面卡頓。 應(yīng)用場(chǎng)景:節(jié)流和防抖的核心其實(shí)就是限制某一個(gè)方法被頻繁觸發(fā),比如說(shuō)DOM事件的監(jiān)聽(tīng)回調(diào),input的keyup、keydown...

    MasonEast 評(píng)論0 收藏0
  • 剖析前端開(kāi)發(fā)中的防抖和節(jié)流

    摘要:運(yùn)用防抖和節(jié)流可以有效降低代碼的執(zhí)行頻率,從而解決高頻率事件的頁(yè)面卡頓問(wèn)題。在階段布局,最終確定顯示的位置和大小。在函數(shù)中,首先定義了一個(gè)空的定時(shí)器變量,用來(lái)計(jì)算時(shí)間間隔。還有一點(diǎn)要注意,在中一定要清楚定時(shí)器,不然會(huì)影響的條件判斷。 啥是節(jié)流? 節(jié)流是保證在一段時(shí)間內(nèi),代碼只執(zhí)行了一次。這個(gè)一段時(shí)間內(nèi)指的是不管用戶操作了幾次,最終僅執(zhí)行一次。比如說(shuō)一個(gè)按鈕,用戶狂點(diǎn)按鈕,但是如果用節(jié)流...

    andong777 評(píng)論0 收藏0
  • 剖析前端開(kāi)發(fā)中的防抖和節(jié)流

    摘要:運(yùn)用防抖和節(jié)流可以有效降低代碼的執(zhí)行頻率,從而解決高頻率事件的頁(yè)面卡頓問(wèn)題。在階段布局,最終確定顯示的位置和大小。在函數(shù)中,首先定義了一個(gè)空的定時(shí)器變量,用來(lái)計(jì)算時(shí)間間隔。還有一點(diǎn)要注意,在中一定要清楚定時(shí)器,不然會(huì)影響的條件判斷。 啥是節(jié)流? 節(jié)流是保證在一段時(shí)間內(nèi),代碼只執(zhí)行了一次。這個(gè)一段時(shí)間內(nèi)指的是不管用戶操作了幾次,最終僅執(zhí)行一次。比如說(shuō)一個(gè)按鈕,用戶狂點(diǎn)按鈕,但是如果用節(jié)流...

    LeexMuller 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<