防抖&截流

/**
 * 防抖函數(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()
    }
  }
}
/**
 * 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;
    };
  };

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市河胎,隨后出現(xiàn)的幾起案子闯袒,更是在濱河造成了極大的恐慌,老刑警劉巖游岳,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件政敢,死亡現(xiàn)場離奇詭異,居然都是意外死亡胚迫,警方通過查閱死者的電腦和手機(jī)喷户,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來访锻,“玉大人褪尝,你說我怎么就攤上這事闹获。” “怎么了河哑?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵避诽,是天一觀的道長。 經(jīng)常有香客問我璃谨,道長沙庐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任佳吞,我火速辦了婚禮拱雏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘底扳。我一直安慰自己古涧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布花盐。 她就那樣靜靜地躺著,像睡著了一般菇爪。 火紅的嫁衣襯著肌膚如雪算芯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天凳宙,我揣著相機(jī)與錄音熙揍,去河邊找鬼。 笑死氏涩,一個胖子當(dāng)著我的面吹牛届囚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播是尖,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼意系,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饺汹?” 一聲冷哼從身側(cè)響起蛔添,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兜辞,沒想到半個月后迎瞧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡逸吵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年凶硅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扫皱。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡足绅,死狀恐怖捷绑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情编检,我是刑警寧澤胎食,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站允懂,受9級特大地震影響厕怜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕾总,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一粥航、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧生百,春花似錦递雀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至市俊,卻和暖如春杨凑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摆昧。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工撩满, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绅你。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓伺帘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忌锯。 傳聞我的和親對象是個殘疾皇子伪嫁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一、前言 在前端開發(fā)中會遇到一些頻繁的事件觸發(fā)偶垮,比如:window 的 resize礼殊、scrollmousedow...
    DY_alley閱讀 2,132評論 0 0
  • 由來 如果短時間以很高頻率觸發(fā) scroll 、resize针史、click 等事件(事件中涉及到大量的位置計算晶伦、DO...
    my木子閱讀 1,395評論 0 1
  • 防抖:就是指觸發(fā)事件后在 n 秒內(nèi)函數(shù)只能執(zhí)行一次,如果在 n 秒內(nèi)又觸發(fā)了事件啄枕,則會重新計算函數(shù)執(zhí)行時間婚陪。 截流...
    小強(qiáng)流浪記閱讀 240評論 0 0
  • 防抖與節(jié)流 防抖,頻繁操作僅觸發(fā)一次 截流频祝,頻繁操作泌参,間隔觸發(fā)
    青銅不黑鐵閱讀 163評論 0 0
  • 防抖 運(yùn)行方式:在第一次觸發(fā)事件時脆淹,不立即執(zhí)行函數(shù),而是給出一個期限值比比如200ms沽一,1盖溺,如果在200ms內(nèi)沒有...
    追夢_3c87閱讀 1,781評論 0 0