亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

Mike617 / 3150人閱讀

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

定義

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

區(qū)別

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

影響

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

實(shí)現(xiàn) 去抖 debounce

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

【簡(jiǎn)潔版】

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

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

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

    // 當(dāng)返回的函數(shù)被最后一次調(diào)用后(也就是用戶停止了某個(gè)連續(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)
    }
}
// 測(cè)試:
var fn = function() {
    console.log("debounce..")
}
oDiv.addEventListener("click", debounce(fn, 3000))
節(jié)流 throttle

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

【簡(jiǎn)潔版】

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

【完整版】

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

游戲射擊,keydown 事件

文本輸入、自動(dòng)完成,keyup 事件

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

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

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

underscore 實(shí)現(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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

    王軍 評(píng)論0 收藏0

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<