国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS - debounce(去抖) 和 throttle(節(jié)流)

Mike617 / 3086人閱讀

摘要:多次連續(xù)事件觸發(fā)動作最后一次觸發(fā)之后的指定時間間隔執(zhí)行回調(diào)函數(shù)預(yù)先設(shè)定一個執(zhí)行周期,當(dāng)調(diào)用動作的時刻大于等于執(zhí)行周期則執(zhí)行該動作,然后進(jìn)入下一個新的時間周期。

定義

為了避免某個事件在較短的時間段內(nèi)(稱為 T)內(nèi)連續(xù)觸發(fā)從而引起的其對應(yīng)的事件處理函數(shù)不必要的連續(xù)執(zhí)行的一種事件處理機(jī)制(高頻觸發(fā)事件解決方案)
debounce:當(dāng)調(diào)用動作觸發(fā)一段時間后,才會執(zhí)行該動作,若在這段時間間隔內(nèi)又調(diào)用此動作則將重新計算時間間隔。(多次連續(xù)事件觸發(fā)動作/最后一次觸發(fā)之后的指定時間間隔執(zhí)行回調(diào)函數(shù))
throttle:預(yù)先設(shè)定一個執(zhí)行周期,當(dāng)調(diào)用動作的時刻大于等于執(zhí)行周期則執(zhí)行該動作,然后進(jìn)入下一個新的時間周期。(每個指定時間執(zhí)行一次回調(diào)函數(shù),可以指定時間間隔之前調(diào)用)

區(qū)別

1、throttle 保證了在每個 T 內(nèi)至少執(zhí)行一次,而 debounce 沒有這樣的保證
2、每次事件觸發(fā)時參考的時間點,對于debounce來是上一次事件觸發(fā)的時間并且在延時沒有結(jié)束時會重置延時;
throttle上一次 handler 執(zhí)行的時間并且在延時尚未結(jié)束時不會重置延時

影響

響應(yīng)速度跟不上觸發(fā)頻率,往往會出現(xiàn)延遲,導(dǎo)致假死或者卡頓感

實現(xiàn) 去抖 debounce

空閑控制:所有操作最后一次性執(zhí)行

【簡潔版】

/**
* @param fn {Function}   實際要執(zhí)行的函數(shù)
* @param delay {Number}  延遲時間,也就是閾值,單位是毫秒(ms)
* @return {Function}     返回一個“去彈跳”了的函數(shù)
*/
function debounce(fn, delay) {
  // 定時器,用來 setTimeout
  var timer

  // 返回一個函數(shù),這個函數(shù)會在一個時間區(qū)間結(jié)束后的 delay 毫秒時執(zhí)行 fn 函數(shù)
  return function () {
    // 保存函數(shù)調(diào)用時的上下文和參數(shù),傳遞給 fn
    var context = this
    var args = arguments

    // 每次這個返回的函數(shù)被調(diào)用,就清除定時器,以保證不執(zhí)行 fn
    clearTimeout(timer)

    // 當(dāng)返回的函數(shù)被最后一次調(diào)用后(也就是用戶停止了某個連續(xù)的操作),
    // 再過 delay 毫秒就執(zhí)行 fn
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}

【完整版】

// immediate: 是否立即執(zhí)行回調(diào)函數(shù); 其它參數(shù)同上
function debounce(fn, wait, immediate) {
    let timer = null

    return function() {
        let args = [].slice.call(arguments)

        if (immediate && !timer) {
            fn.apply(this, args)
        }

        if (timer) clearTimeout(timer)
        timer = setTimeout(() => { //箭頭函數(shù),this指向外層環(huán)境
            fn.apply(this, args)
        }, wait)
    }
}
// 測試:
var fn = function() {
    console.log("debounce..")
}
oDiv.addEventListener("click", debounce(fn, 3000))
節(jié)流 throttle

固定頻次:減少執(zhí)行頻次,每隔一定時間執(zhí)行一次

【簡潔版】

/**
* 固定回調(diào)函數(shù)執(zhí)行的頻次
* @param fn {Function}   實際要執(zhí)行的函數(shù)
* @param interval {Number}  執(zhí)行間隔,單位是毫秒(ms)
*
* @return {Function}     返回一個“節(jié)流”函數(shù)
*/
var throttle = function (fn, interval) {
  // 記錄前一次時間
  var last = +new Date()
  var timer = null
  // 包裝完后返回 閉包函數(shù)
  return function () {
    var current = +new Date()
    var args = [].slice.call(arguments, 0)
    var context = this
    // 首先清除定時器
    clearTimeout(timer)
    // current 與last 間隔大于interval 執(zhí)行一次fn
    // 在一個周期內(nèi) last相對固定 current一直再增加
    // 這里可以保證調(diào)用很密集的情況下 current和last 必須是相隔interval 才會調(diào)用fn
    if (current - last >= interval) {
      fn.apply(context, args)
      last = current
    } else {
      // 如果沒有大于間隔 添加定時器
      // 這可以保證 即使后面沒有再次觸發(fā) fn也會在規(guī)定的interval后被調(diào)用
      timer = setTimeout(function() {
        fn.apply(context, args)
        last = current
      }, interval-(current - last))
    }
  }
}

【完整版】

/**
 * 頻率控制 返回函數(shù)連續(xù)調(diào)用時,func 執(zhí)行頻率限定為 次 / wait
 * 自動合并 data
 * 
 * 若無 option 選項,或者同時為true,即 option.trailing !== false && option.leading !== false,在固定時間開始時刻調(diào)用一次回調(diào),并每個固定時間最后時刻調(diào)用回調(diào)
 * 若 option.trailing !== false && option.leading === false, 每個固定時間最后時刻調(diào)用回調(diào)
 * 若 option.trailing === false && option.leading  !== false,  只會在固定時間開始時刻調(diào)用一次回調(diào)
 * 若同時為false 則不會被調(diào)用
 *
 * @param  {function}   func      傳入函數(shù)
 * @param  {number}     wait      表示時間窗口的間隔
 * @param  {object}     options   如果想忽略開始邊界上的調(diào)用,傳入{leading: false}。默認(rèn)undefined
 *                                如果想忽略結(jié)尾邊界上的調(diào)用,傳入{trailing: false}, 默認(rèn)undefined
 * @return {function}             返回客戶調(diào)用函數(shù)
 */
function throttle (func, wait, options) {
  var context, args, result;
  var timeout = null;
  // 上次執(zhí)行時間點
  var previous = 0;
  if (!options) { options = {}; }
  // 延遲執(zhí)行函數(shù)
  function later () {
    // 若設(shè)定了開始邊界不執(zhí)行選項,上次執(zhí)行時間始終為0
    previous = options.leading === false ? 0 : Date.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) { context = args = null; }
  }
  return function (handle, data) {
    var now = Date.now();
    // 首次執(zhí)行時,如果設(shè)定了開始邊界不執(zhí)行選項,將上次執(zhí)行時間設(shè)定為當(dāng)前時間。
    if (!previous && options.leading === false) { previous = now; }
    // 延遲執(zhí)行時間間隔
    var remaining = wait - (now - previous);
    context = this;
    args = args ? [handle, Object.assign(args[1], data)] : [handle, data];
    // 延遲時間間隔remaining小于等于0,表示上次執(zhí)行至此所間隔時間已經(jīng)超過一個時間窗口
    // remaining大于時間窗口wait,表示客戶端系統(tǒng)時間被調(diào)整過
    if (remaining <= 0 || remaining > wait) {
      clearTimeout(timeout);
      timeout = null;
      previous = now;
      result = func.apply(context, args);
      if (!timeout) { context = args = null; }
    // 如果延遲執(zhí)行不存在,且沒有設(shè)定結(jié)尾邊界不執(zhí)行選項
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result
  }
}
運用

游戲射擊,keydown 事件

文本輸入、自動完成,keyup 事件

鼠標(biāo)移動,mousemove 事件

DOM 元素動態(tài)定位,window 對象的 resize 和 scroll 事件

前兩者 debounce 和 throttle 都可以按需使用;后兩者肯定是用 throttle

underscore 實現(xiàn)源碼 debounce
_.debounce = function(func, wait, immediate) {
  var timeout, result;

  var later = function(context, args) {
    timeout = null;
    if (args) result = func.apply(context, args);
  };

  var debounced = restArgs(function(args) {
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(later, wait);
      if (callNow) result = func.apply(this, args);
    } else {
      timeout = _.delay(later, wait, this, args);
    }

    return result;
  });

  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  };

  return debounced;
};
throttle
 _.throttle = function(func, wait, options) {
  var timeout, context, args, result;
  var previous = 0;
  if (!options) options = {};

  var later = function() {
    previous = options.leading === false ? 0 : _.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };

  var throttled = function() {
    var now = _.now();
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result;
  };

  throttled.cancel = function() {
    clearTimeout(timeout);
    previous = 0;
    timeout = context = args = null;
  };

  return throttled;
};

【參考】
https://blog.coding.net/blog/...
https://github.com/lishengzxc...

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/105533.html

相關(guān)文章

  • JS中的函數(shù)去抖節(jié)流

    摘要:上段代碼的一個問題是,事件會在定時器結(jié)束后被觸發(fā),因此會出現(xiàn)一定的延遲,如果想讓事件被立即觸發(fā),可以使用以下的去抖函數(shù)但是,對于去抖來說,在某些場景下是不合適的,因此我們可以使用節(jié)流。 參考文章游戲星人眼中的節(jié)流與去抖(很生動) 函數(shù)去抖與節(jié)流 Debounce:函數(shù)去抖就是對于一定時間段的連續(xù)的函數(shù)調(diào)用,只讓其執(zhí)行一次Throttle:函數(shù)節(jié)流就是讓連續(xù)執(zhí)行的函數(shù),變成固定時間段間斷...

    fuchenxuan 評論0 收藏0
  • JS throttledebounce的區(qū)別

    摘要:可以看下面的栗子這個圖中圖中每個小格大約,右邊有原生事件與節(jié)流去抖插件的與事件。即如果有連續(xù)不斷的觸發(fā),每執(zhí)行一次,用在每隔一定間隔執(zhí)行回調(diào)的場景。執(zhí)行啦打印執(zhí)行啦打印執(zhí)行啦節(jié)流按照上面的說明,節(jié)流就是連續(xù)多次內(nèi)的操作按照指定的間隔來執(zhí)行。 一般在項目中我們會對input、scroll、resize等事件進(jìn)行節(jié)流控制,防止事件過多觸發(fā),減少資源消耗;在vue的官網(wǎng)的例子中就有關(guān)于lod...

    wawor4827 評論0 收藏0
  • 函數(shù)節(jié)流throttle)與函數(shù)去抖debounce

    摘要:去抖主要針對的是頻繁觸發(fā)某個事件后,然后進(jìn)行后續(xù)處理的場景。常見的就是頻繁輸入停止假設(shè)后進(jìn)行查詢等操作。函數(shù)接口定義實際需要調(diào)用的函數(shù)空閑時間返回調(diào)用函數(shù)函數(shù)接口定義延遲時間需要調(diào)用的函數(shù)返回函數(shù) 前言 做過前端的童鞋應(yīng)該都知道lodash這個強(qiáng)大的使用工具庫。為什么要寫這篇文章呢,主要今天遇到一個問題,socket推送消息太頻繁,導(dǎo)致saga頻繁更新,頁面有所卡頓,需要通過函數(shù)節(jié)流控...

    bergwhite 評論0 收藏0
  • JavaScript 函數(shù)節(jié)流函數(shù)去抖應(yīng)用場景辨析

    摘要:函數(shù)節(jié)流和去抖的出現(xiàn)場景,一般都伴隨著客戶端的事件監(jiān)聽。函數(shù)節(jié)流的核心是,讓一個函數(shù)不要執(zhí)行得太頻繁,減少一些過快的調(diào)用來節(jié)流。 概述 也是好久沒更新 源碼解讀,看著房價蹭蹭暴漲,心里也是五味雜陳,對未來充滿恐懼和迷茫 ...(敢問一句你們上岸了嗎) 言歸正傳,今天要介紹的是 underscore 中兩個重要的方法,函數(shù)節(jié)流和函數(shù)去抖。這篇文章不會涉及具體的代碼實現(xiàn)(關(guān)于代碼實現(xiàn)請期...

    ZHAO_ 評論0 收藏0
  • js中函數(shù)節(jié)流&函數(shù)去抖

    摘要:節(jié)流保證在一定時間內(nèi),只能觸發(fā)一次。我們在嘗試一下去抖消抖,消除抖動,感覺這個更好聽有沒有什么現(xiàn)成的上的一次發(fā)現(xiàn)源碼的經(jīng)歷以及對學(xué)術(shù)界拿來主義的思考函數(shù)節(jié)流和函數(shù)去抖應(yīng)用場景辨析函數(shù)去抖的實現(xiàn) 開篇先提幾個問題? 1.做搜索框的時候你使用什么事件?change?blur?keyup?你想要的效果是什么? 2.scroll事件怎么就觸發(fā)?是滾一段距離觸發(fā)一次?還是滾一圈觸發(fā)一次?還是滾...

    王軍 評論0 收藏0

發(fā)表評論

0條評論

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