国产69囗曝吞精在线视频,肥臀浪妇太爽了快点再快点,亚洲欧洲成人a∨在线观看,狠狠色丁香久久综合 ,国精一二二产品无人区免费应用,亚洲精品久久久久中文字幕,四虎一区二区成人免费影院网址 ,无码三级中文字幕在线观看

      函數(shù)節(jié)流與函數(shù)防抖的區(qū)別

      2020-4-29    seo達(dá)人

      函數(shù)節(jié)流與函數(shù)防抖是我們解決頻繁觸發(fā)DOM事件的兩種常用解決方案,但是經(jīng)常傻傻分不清楚。。。這不,在項(xiàng)目中又用遇到了,在此處記錄一下



      函數(shù)防抖 debounce

      原理:將若干函數(shù)調(diào)用合成為一次,并在給定時(shí)間過去之后,或者連續(xù)事件完全觸發(fā)完成之后,調(diào)用一次(僅僅只會(huì)調(diào)用一次!!!!!!!!!!)。



      舉個(gè)栗子:滾動(dòng)scroll事件,不停滑動(dòng)滾輪會(huì)連續(xù)觸發(fā)多次滾動(dòng)事件,從而調(diào)用綁定的回調(diào)函數(shù),我們希望當(dāng)我們停止?jié)L動(dòng)的時(shí),才觸發(fā)一次回調(diào),這時(shí)可以使用函數(shù)防抖。



      原理性代碼及測(cè)試:



      // 給盒子較大的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) // 每次調(diào)用debounce函數(shù)都會(huì)將前一次的timer清空,確保只執(zhí)行一次

                          timer = setTimeout(() => {

                              fn.apply(context, args)

                          }, delay)

                      }

                  }



                  let num = 0



                  function scrollTap() {

                      num++

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

                  }

                  // 此處的觸發(fā)時(shí)間間隔設(shè)置的很小

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

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

              }

          </script>

      </body>



      此處的觸發(fā)時(shí)間間隔設(shè)置的很小,如果勻速不間斷的滾動(dòng),不斷觸發(fā)scroll事件,如果不用debounce處理,可以發(fā)現(xiàn)num改變了很多次,用了debounce函數(shù)防抖,num在一次上時(shí)間的滾動(dòng)中只改變了一次。



      調(diào)用debouce使scrollTap防抖之后的結(jié)果:



      直接調(diào)用scrollTap的結(jié)果:





      補(bǔ)充:瀏覽器在處理setTimeout和setInterval時(shí),有最小時(shí)間間隔。

      setTimeout的最短時(shí)間間隔是4毫秒;

      setInterval的最短間隔時(shí)間是10毫秒,也就是說,小于10毫秒的時(shí)間間隔會(huì)被調(diào)整到10毫秒。

      事實(shí)上,未優(yōu)化時(shí),scroll事件頻繁觸發(fā)的時(shí)間間隔也是這個(gè)最小時(shí)間間隔。

      也就是說,當(dāng)我們?cè)赿ebounce函數(shù)中的間隔事件設(shè)置不恰當(dāng)(小于這個(gè)最小時(shí)間間隔),會(huì)使debounce無效。



      函數(shù)節(jié)流 throttle

      原理:當(dāng)達(dá)到了一定的時(shí)間間隔就會(huì)執(zhí)行一次;可以理解為是縮減執(zhí)行頻率



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



      原理性代碼及實(shí)現(xiàn)



      // 函數(shù)節(jié)流 throttle

      // 方法一:定時(shí)器實(shí)現(xiàn)

      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)

          }

        }

      }



      // 方法二:時(shí)間戳

      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()

            }

        }

      }



      需要注意的是定時(shí)器方法實(shí)現(xiàn)throttle方法和debounce方法的不同:



      在debounce中:在執(zhí)行setTimeout函數(shù)之前總會(huì)將timer用setTimeout清除,取消延遲代碼塊,確保只執(zhí)行一次

      在throttle中:只要timer存在就會(huì)執(zhí)行setTimeout,在setTimeout內(nèi)部每次清空這個(gè)timer,但是延遲代碼塊已經(jīng)執(zhí)行啦,確保一定頻率執(zhí)行一次




      我們依舊可以在html頁面中進(jìn)行測(cè)試scroll事件,html和css代碼同debounce,此處不贅述,運(yùn)行結(jié)果是(可以說是一場(chǎng)漫長(zhǎng)的滾輪滾動(dòng)了):





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



      /*

       
      空閑控制 返回函數(shù)連續(xù)調(diào)用時(shí),空閑時(shí)間必須大于或等于 wait,func 才會(huì)執(zhí)行

       

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

        @param  {number}   wait        表示時(shí)間窗口的間隔

       
      @param  {boolean}  immediate   設(shè)置為ture時(shí),調(diào)用觸發(fā)于開始邊界而不是結(jié)束邊界

        @return {function}             返回客戶調(diào)用函數(shù)

       
      /

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

          let timeout, args, context, timestamp, result;



          const later = function() {

              // 據(jù)上一次觸發(fā)時(shí)間間隔

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



              // 上次被包裝函數(shù)被調(diào)用時(shí)間間隔last小于設(shè)定時(shí)間間隔wait

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

                  timeout = setTimeout(later, wait - last);

              } else {

                  timeout = null;

                  // 如果設(shè)定為immediate===true,因?yàn)殚_始邊界已經(jīng)調(diào)用過了此處無需調(diào)用

                  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;

              // 如果延時(shí)不存在,重新設(shè)定延時(shí)

              if (!timeout) {

                  timeout = setTimeout(later, wait);

              }

              if (callNow) {

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

                  context = args = null;

              }



              return result;

          };

      };



      /*

       
      頻率控制 返回函數(shù)連續(xù)調(diào)用時(shí),func 執(zhí)行頻率限定為 次 / wait

       

       
      @param  {function}   func      傳入函數(shù)

        @param  {number}     wait      表示時(shí)間窗口的間隔

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

                                       如果想忽略結(jié)尾邊界上的調(diào)用,傳入{trailing: false}

       
      @return {function}             返回客戶調(diào)用函數(shù)

       */

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

          let context, args, result;

          let timeout = null;

          // 上次執(zhí)行時(shí)間點(diǎn)

          let previous = 0;

          if (!options) options = {};

          // 延遲執(zhí)行函數(shù)

          let later = function() {

              // 若設(shè)定了開始邊界不執(zhí)行選項(xiàng),上次執(zhí)行時(shí)間始終為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());

              // 首次執(zhí)行時(shí),如果設(shè)定了開始邊界不執(zhí)行選項(xiàng),將上次執(zhí)行時(shí)間設(shè)定為當(dāng)前時(shí)間。

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

              // 延遲執(zhí)行時(shí)間間隔

              let remaining = wait - (now - previous);

              context = this;

              args = _args;

              // 延遲時(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;

          };

      };


      日歷

      鏈接

      個(gè)人資料

      存檔

      主站蜘蛛池模板: 精品国产一区二区三区不卡在线| 日本xxx在线播放| 国产精品va尤物在线观看蜜芽 | 日本美女性亚洲精品黄色| 国产自美女在线精品尤物| 婷婷狠狠爱| 日韩人妻中文字幕精品| 国产精选bt天堂| 亚洲一区二区久久| 免费a v网站| 国产99视频精品免视看7| 久久人人97超碰精品| 中文字幕无码人妻少妇免费| 国产免费无遮挡吸乳视频| 国产午夜理论片不卡| 黄色片91| 欧美激情福利| 日本牲交大片无遮挡| 久青青视频在线观看久| 欧美日本韩国| 欧美黑人巨大videos精品| 国产精品永久视频免费| 久久动态图| 国产成人精品综合| 无码毛片视频一区二区本码| 久久不见久久见免费影院小说 | av网站有哪些| 国产中文字幕乱人伦在线观看 | 男人久久天堂| 亚洲精品无播放器在线播放| 亚洲精品无码av黄瓜影视| 中文字幕日本人妻久久久免费| 国产一区二区三区av在线无码观看| 亚洲婷婷五月综合狠狠app| 午夜电影网站| 欧美成人手机视频| 中文无码av一区二区三区| 亚洲视频一区二区| 污漫在线观看| 国产成人精品中文字幕| 国产亚洲日韩a欧美在线人成|