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

資訊專欄INFORMATION COLUMN

淺談節(jié)流與防抖

thursday / 2810人閱讀

摘要:節(jié)流和防抖在開發(fā)項目過程中很常見,例如輸入實時搜索滾動更新了,等等,大量的場景需要我們對其進(jìn)行處理。防抖多次觸發(fā),只在最后一次觸發(fā)時,執(zhí)行目標(biāo)函數(shù)。節(jié)流限制目標(biāo)函數(shù)調(diào)用的頻率,比如內(nèi)不能調(diào)用次。

節(jié)流和防抖在開發(fā)項目過程中很常見,例如 input 輸入實時搜索、scrollview 滾動更新了,等等,大量的場景需要我們對其進(jìn)行處理。我們由 Lodash 來介紹,直接進(jìn)入主題吧。

Lodash API

防抖 (debounce) :多次觸發(fā),只在最后一次觸發(fā)時,執(zhí)行目標(biāo)函數(shù)。

lodash.debounce(func, [wait=0], [options={}])

節(jié)流(throttle):限制目標(biāo)函數(shù)調(diào)用的頻率,比如:1s內(nèi)不能調(diào)用2次。

lodash.throttle(func, [wait=0], [options={}])

lodash 在 opitons 參數(shù)中定義了一些選項,主要是以下三個:

leading:函數(shù)在每個等待時延的開始被調(diào)用,默認(rèn)值為false

trailing:函數(shù)在每個等待時延的結(jié)束被調(diào)用,默認(rèn)值是true

maxwait:最大的等待時間,因為如果 debounce 的函數(shù)調(diào)用時間不滿足條件,可能永遠(yuǎn)都無法觸發(fā),因此增加了這個配置,保證大于一段時間后一定能執(zhí)行一次函數(shù)

根據(jù) leading 和 trailing 的組合,可以實現(xiàn)不同的調(diào)用效果:

{leading: true, trailing: false}:只在延時開始時調(diào)用

{leading: false, trailing: true}:默認(rèn)情況,即在延時結(jié)束后才會調(diào)用函數(shù)

{leading: true, trailing: true}:在延時開始時就調(diào)用,延時結(jié)束后也會調(diào)用

deboucne 還有 cancel 方法,用于取消防抖動調(diào)用

使用

防抖 (debounce):

addEntity = () => {
  console.log("--------------addEntity---------------")
  this.debounceFun();
}
 
debounceFun = lodash.debounce(function(e){
  console.log("--------------debounceFun---------------");
}, 500,{
  leading: true,
  trailing: false,
})

首次點擊時執(zhí)行,連續(xù)點擊且時間間隔在500ms之內(nèi),不再執(zhí)行,間隔在500ms之外再次點擊,執(zhí)行。

節(jié)流(throttle):

addEntity = () => {
  console.log("--------------addEntity---------------");
  this.throttleFun();
}
 
throttleFun = lodash.throttle(function(e){
  console.log("--------------throttleFun---------------");
}, 500,{
  leading: true,
  trailing: false,
})

首次點擊時執(zhí)行,連續(xù)點擊且間隔在500ms之內(nèi),500ms之后自動執(zhí)行一次(注:連續(xù)點擊次數(shù)時間之后小于500ms,則不會自動執(zhí)行),間隔在500ms之外再次點擊,執(zhí)行。

源碼實現(xiàn) debounce
// 這個是用來獲取當(dāng)前時間戳的
function now() {
  return +new Date()
}
/**
 * 防抖函數(shù),返回函數(shù)連續(xù)調(diào)用時,空閑時間必須大于或等于 wait,func 才會執(zhí)行
 *
 * @param  {function} func        回調(diào)函數(shù)
 * @param  {number}   wait        表示時間窗口的間隔
 * @param  {boolean}  immediate   設(shè)置為ture時,是否立即調(diào)用函數(shù)
 * @return {function}             返回客戶調(diào)用函數(shù)
 */
function debounce (func, wait = 50, immediate = true) {
  let timer, context, args

  // 延遲執(zhí)行函數(shù)
  const later = () => setTimeout(() => {
    // 延遲函數(shù)執(zhí)行完畢,清空緩存的定時器序號
    timer = null
    // 延遲執(zhí)行的情況下,函數(shù)會在延遲函數(shù)中執(zhí)行
    // 使用到之前緩存的參數(shù)和上下文
    if (!immediate) {
      func.apply(context, args)
      context = args = null
    }
  }, wait)

  // 這里返回的函數(shù)是每次實際調(diào)用的函數(shù)
  return function(...params) {
    // 如果沒有創(chuàng)建延遲執(zhí)行函數(shù)(later),就創(chuàng)建一個
    if (!timer) {
      timer = later()
      // 如果是立即執(zhí)行,調(diào)用函數(shù)
      // 否則緩存參數(shù)和調(diào)用上下文
      if (immediate) {
        func.apply(this, params)
      } else {
        context = this
        args = params
      }
    // 如果已有延遲執(zhí)行函數(shù)(later),調(diào)用的時候清除原來的并重新設(shè)定一個
    // 這樣做延遲函數(shù)會重新計時
    } else {
      clearTimeout(timer)
      timer = later()
    }
  }
}
throttle
/**
 * underscore 節(jié)流函數(shù),返回函數(shù)連續(xù)調(diào)用時,func 執(zhí)行頻率限定為 次 / wait
 *
 * @param  {function}   func      回調(diào)函數(shù)
 * @param  {number}     wait      表示時間窗口的間隔
 * @param  {object}     options   如果想忽略開始函數(shù)的的調(diào)用,傳入{leading: false}。
 *                                如果想忽略結(jié)尾函數(shù)的調(diào)用,傳入{trailing: false}
 *                                兩者不能共存,否則函數(shù)不能執(zhí)行
 * @return {function}             返回客戶調(diào)用函數(shù)
 */
_.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    // 之前的時間戳
    var previous = 0;
    // 如果 options 沒傳則設(shè)為空對象
    if (!options) options = {};
    // 定時器回調(diào)函數(shù)
    var later = function() {
      // 如果設(shè)置了 leading,就將 previous 設(shè)為 0
      // 用于下面函數(shù)的第一個 if 判斷
      previous = options.leading === false ? 0 : _.now();
      // 置空一是為了防止內(nèi)存泄漏,二是為了下面的定時器判斷
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      // 獲得當(dāng)前時間戳
      var now = _.now();
      // 首次進(jìn)入前者肯定為 true
      // 如果需要第一次不執(zhí)行函數(shù)
      // 就將上次時間戳設(shè)為當(dāng)前的
      // 這樣在接下來計算 remaining 的值時會大于0
      if (!previous && options.leading === false) previous = now;
      // 計算剩余時間
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // 如果當(dāng)前調(diào)用已經(jīng)大于上次調(diào)用時間 + wait
      // 或者用戶手動調(diào)了時間
       // 如果設(shè)置了 trailing,只會進(jìn)入這個條件
      // 如果沒有設(shè)置 leading,那么第一次會進(jìn)入這個條件
      // 還有一點,你可能會覺得開啟了定時器那么應(yīng)該不會進(jìn)入這個 if 條件了
      // 其實還是會進(jìn)入的,因為定時器的延時
      // 并不是準(zhǔn)確的時間,很可能你設(shè)置了2秒
      // 但是他需要2.2秒才觸發(fā),這時候就會進(jìn)入這個條件
      if (remaining <= 0 || remaining > wait) {
        // 如果存在定時器就清理掉否則會調(diào)用二次回調(diào)
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // 判斷是否設(shè)置了定時器和 trailing
        // 沒有的話就開啟一個定時器
        // 并且不能不能同時設(shè)置 leading 和 trailing
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

走在最后,歡迎 star:https://github.com/sisterAn/blog

歡迎關(guān)注:前端瓶子君

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

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

相關(guān)文章

  • 理解節(jié)流防抖

    摘要:節(jié)流節(jié)流限制了一個函數(shù)可以在短時間內(nèi)被調(diào)用的次數(shù)。更新防抖防抖確保了一個函數(shù)只有在一個固定時間段內(nèi)沒有被調(diào)用過后,才會再次被調(diào)用。再換句話說防抖會等待事件不再高頻發(fā)生,再觸發(fā)。這個網(wǎng)站很好的可視化了節(jié)流與防抖。 節(jié)流 Throttling 節(jié)流限制了一個函數(shù)可以在短時間內(nèi)被調(diào)用的次數(shù)??梢赃@樣形容:在一毫秒內(nèi)最多執(zhí)行此函數(shù) 1 次。 Throttling enforces a maxi...

    glumes 評論0 收藏0
  • JavaScript之節(jié)流防抖

    摘要:個人博客原文地址背景我們在開發(fā)的過程中會經(jīng)常使用如等事件,如果正常綁定事件處理函數(shù)的話,有可能在很短的時間內(nèi)多次連續(xù)觸發(fā)事件,十分影響性能。 個人博客原文地址 背景 我們在開發(fā)的過程中會經(jīng)常使用如scroll、resize、touchmove等事件,如果正常綁定事件處理函數(shù)的話,有可能在很短的時間內(nèi)多次連續(xù)觸發(fā)事件,十分影響性能。因此針對這類事件要進(jìn)行節(jié)流或者防抖處理 節(jié)流 節(jié)流的意思...

    wayneli 評論0 收藏0
  • 從lodash源碼學(xué)習(xí)節(jié)流防抖

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

    CloudDeveloper 評論0 收藏0
  • The debounce & throttle in Javascript(防抖節(jié)流

    摘要:您的支持是我最大的動力,我會保證提供高質(zhì)與清晰的文章與您共同成長。一些文章中的與上面所談到的設(shè)置類似。防抖防抖技術(shù)允許我們捆綁多個連續(xù)調(diào)用成為單一的一次調(diào)用。防抖的應(yīng)用這個簡單的舉個 歡迎star和watch我的github issue blog,歡迎加入討論。您的支持是我最大的動力,我會保證提供高質(zhì)與清晰的文章與您共同成長。 節(jié)流[throttle]與防抖[debounce]在前...

    XboxYan 評論0 收藏0
  • 節(jié)流 - 理解,實踐與實現(xiàn)

    摘要:節(jié)流分流,與防抖去抖實現(xiàn)原理相似。本文主要討論節(jié)流,鏡像文章防抖理解,實踐與實現(xiàn)。分開討論防抖和節(jié)流,主要是為了讓一些還不太了解節(jié)流防抖的讀者能夠有針對性地,逐一掌握它們。上方為未節(jié)流模式,每一次觸發(fā)都會繪制一個圓點。 showImg(https://segmentfault.com/img/bVbqMwN?w=1280&h=720); 節(jié)流(分流),與防抖(去抖)實現(xiàn)原理相似。本文主...

    layman 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<