• <center id="sm46c"></center>
  • <dfn id="sm46c"></dfn>
  • <strike id="sm46c"></strike>
  • <cite id="sm46c"><source id="sm46c"></source></cite>
    • <strike id="sm46c"><source id="sm46c"></source></strike>
      <option id="sm46c"></option>
      国产精品天天看天天狠,女高中生强奷系列在线播放,久久无码免费的a毛片大全,国产日韩综合av在线,亚洲国产中文综合专区在,特殊重囗味sm在线观看无码,中文字幕一区二区三区四区在线,无码任你躁久久久久久老妇蜜桃

      函數節流與函數防抖的區別

      2020-4-29    seo達人

      函數節流與函數防抖是我們解決頻繁觸發DOM事件的兩種常用解決方案,但是經常傻傻分不清楚。。。這不,在項目中又用遇到了,在此處記錄一下



      函數防抖 debounce

      原理:將若干函數調用合成為一次,并在給定時間過去之后,或者連續事件完全觸發完成之后,調用一次(僅僅只會調用一次!!!!!!!!!!)。



      舉個栗子:滾動scroll事件,不停滑動滾輪會連續觸發多次滾動事件,從而調用綁定的回調函數,我們希望當我們停止滾動的時,才觸發一次回調,這時可以使用函數防抖。



      原理性代碼及測試:



      // 給盒子較大的height,容易看到效果

      <style>

          * {

              padding: 0;

              margin: 0;

          }



          .box {

              width: 800px;

              height: 1200px;

          }

      </style>

      <body>

          <div class="container">

              <div class="box" style="background: tomato"></div>

              <div class="box" style="background: skyblue"></div>

              <div class="box" style="background: red"></div>

              <div class="box" style="background: yellow"></div>

          </div>

          <script>

              window.onload = function() {

                  const decounce = function(fn, delay) {

                      let timer = null



                      return function() {

                          const context = this

                          let args = arguments

                          clearTimeout(timer) // 每次調用debounce函數都會將前一次的timer清空,確保只執行一次

                          timer = setTimeout(() => {

                              fn.apply(context, args)

                          }, delay)

                      }

                  }



                  let num = 0



                  function scrollTap() {

                      num++

                      console.log(看看num吧 ${num})

                  }

                  // 此處的觸發時間間隔設置的很小

                  document.addEventListener('scroll', decounce(scrollTap, 500))

                  // document.addEventListener('scroll', scrollTap)

              }

          </script>

      </body>



      此處的觸發時間間隔設置的很小,如果勻速不間斷的滾動,不斷觸發scroll事件,如果不用debounce處理,可以發現num改變了很多次,用了debounce函數防抖,num在一次上時間的滾動中只改變了一次。



      調用debouce使scrollTap防抖之后的結果:



      直接調用scrollTap的結果:





      補充:瀏覽器在處理setTimeout和setInterval時,有最小時間間隔。

      setTimeout的最短時間間隔是4毫秒;

      setInterval的最短間隔時間是10毫秒,也就是說,小于10毫秒的時間間隔會被調整到10毫秒。

      事實上,未優化時,scroll事件頻繁觸發的時間間隔也是這個最小時間間隔。

      也就是說,當我們在debounce函數中的間隔事件設置不恰當(小于這個最小時間間隔),會使debounce無效。



      函數節流 throttle

      原理:當達到了一定的時間間隔就會執行一次;可以理解為是縮減執行頻率



      舉個栗子:還是以scroll滾動事件來說吧,滾動事件是及其消耗瀏覽器性能的,不停觸發。以我在項目中碰到的問題,移動端通過scroll實現分頁,不斷滾動,我們不希望不斷發送請求,只有當達到某個條件,比如,距離手機窗口底部150px才發送一個請求,接下來就是展示新頁面的請求,不停滾動,如此反復;這個時候就得用到函數節流。



      原理性代碼及實現



      // 函數節流 throttle

      // 方法一:定時器實現

      const throttle = function(fn,delay) {

        let timer = null



        return function() {

          const context = this

          let args = arguments

          if(!timer) {

            timer = setTimeout(() => {

              fn.apply(context,args) 

              clearTimeout(timer) 

            },delay)

          }

        }

      }



      // 方法二:時間戳

      const throttle2 = function(fn, delay) {

        let preTime = Date.now()



        return function() {

            const context = this

            let args = arguments

            let doTime = Date.now()

            if (doTime - preTime >= delay) {

                fn.apply(context, args)

                preTime = Date.now()

            }

        }

      }



      需要注意的是定時器方法實現throttle方法和debounce方法的不同:



      在debounce中:在執行setTimeout函數之前總會將timer用setTimeout清除,取消延遲代碼塊,確保只執行一次

      在throttle中:只要timer存在就會執行setTimeout,在setTimeout內部每次清空這個timer,但是延遲代碼塊已經執行啦,確保一定頻率執行一次




      我們依舊可以在html頁面中進行測試scroll事件,html和css代碼同debounce,此處不贅述,運行結果是(可以說是一場漫長的滾輪滾動了):





      最后再來瞅瞅項目中封裝好的debounce和throttle函數,可以說是很優秀了,考慮的特別全面,希望自己以后封裝的函數也能考慮的這么全面吧,加油!



      /*

       
      空閑控制 返回函數連續調用時,空閑時間必須大于或等于 wait,func 才會執行

       

       
      @param  {function} func        傳入函數,最后一個參數是額外增加的this對象,.apply(this, args) 這種方式,this無法傳遞進函數

        @param  {number}   wait        表示時間窗口的間隔

       
      @param  {boolean}  immediate   設置為ture時,調用觸發于開始邊界而不是結束邊界

        @return {function}             返回客戶調用函數

       
      /

      const debounce = function(func, wait, immediate) {

          let timeout, args, context, timestamp, result;



          const later = function() {

              // 據上一次觸發時間間隔

              let last = Number(new Date()) - timestamp;



              // 上次被包裝函數被調用時間間隔last小于設定時間間隔wait

              if (last < wait && last > 0) {

                  timeout = setTimeout(later, wait - last);

              } else {

                  timeout = null;

                  // 如果設定為immediate===true,因為開始邊界已經調用過了此處無需調用

                  if (!immediate) {

                      result = func.call(context, ...args, context);

                      if (!timeout) {

                          context = args = null;

                      }

                  }

              }

          };



          return function(..._args) {

              context = this;

              args = _args;

              timestamp = Number(new Date());

              const callNow = immediate && !timeout;

              // 如果延時不存在,重新設定延時

              if (!timeout) {

                  timeout = setTimeout(later, wait);

              }

              if (callNow) {

                  result = func.call(context, ...args, context);

                  context = args = null;

              }



              return result;

          };

      };



      /*

       
      頻率控制 返回函數連續調用時,func 執行頻率限定為 次 / wait

       

       
      @param  {function}   func      傳入函數

        @param  {number}     wait      表示時間窗口的間隔

       
      @param  {object}     options   如果想忽略開始邊界上的調用,傳入{leading: false}。

                                       如果想忽略結尾邊界上的調用,傳入{trailing: false}

       
      @return {function}             返回客戶調用函數

       */

      const throttle = function(func, wait, options) {

          let context, args, result;

          let timeout = null;

          // 上次執行時間點

          let previous = 0;

          if (!options) options = {};

          // 延遲執行函數

          let later = function() {

              // 若設定了開始邊界不執行選項,上次執行時間始終為0

              previous = options.leading === false ? 0 : Number(new Date());

              timeout = null;

              result = func.apply(context, args);

              if (!timeout) context = args = null;

          };

          return function(..._args) {

              let now = Number(new Date());

              // 首次執行時,如果設定了開始邊界不執行選項,將上次執行時間設定為當前時間。

              if (!previous && options.leading === false) previous = now;

              // 延遲執行時間間隔

              let remaining = wait - (now - previous);

              context = this;

              args = _args;

              // 延遲時間間隔remaining小于等于0,表示上次執行至此所間隔時間已經超過一個時間窗口

              // remaining大于時間窗口wait,表示客戶端系統時間被調整過

              if (remaining <= 0 || remaining > wait) {

                  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;

          };

      };


      日歷

      鏈接

      個人資料

      藍藍設計的小編 http://www.li-bodun.cn

      存檔

      主站蜘蛛池模板: 国产一区二区三区免费观看在线 | 国产午夜福利av在线麻豆| 国产精品一区二区蜜臀av| 99在线国产| 亚洲AV鲁丝一区二区三区| 人妻忍着娇喘被中进中出视频| 扒开双腿猛进入喷水高潮叫声 | 曰本a∨久久综合久久| 中文字幕无码人妻少妇免费| 亚洲欧美人成电影在线观看| 小荡货奶真大水真多紧视频| 免费无码成人av片在线| 国产日韩另类综合11页| 亚洲精品无码AV人在线观看国产| 在线精品视频一区二区三区| 国产成人精品亚洲午夜| 综合久青草视频在线观看| 亚洲女人在线| 凹凸国产熟女精品视频app| 18禁无遮挡啪啪无码网站破解版 | 成人精品一区日本无码网站| 天天爽夜夜爽人人爽一区二区| 又爽又黄又无遮挡的激情视频| 色狠狠色婷婷丁香五月| 中文亚洲成A人片在线观看| yy111111在线尤物| 国产精品视频一区不卡| 99国产精品自在自在久久| 国产成人手机高清在线观看网站| 天天爱天天做天天爽| 国产亚洲精品欧洲在线视频| 国产一区国产二区在线精品| 在线播放无码字幕亚洲| 亚洲欧美自偷自拍视频图片| 欧美大屁股喷潮水xxxx| 精品无码成人片一区二区| 熟女人妻水多爽中文字幕| av大片在线无码免费| 亚洲aⅴ无码成人网站国产| 蜜臀av一区二区三区日韩 | 老司机午夜精品视频资源|