嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片

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

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

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



函數(shù)防抖 debounce

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



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



原理性代碼及測試:



// 給盒子較大的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ù)都會將前一次的timer清空,確保只執(zhí)行一次

                    timer = setTimeout(() => {

                        fn.apply(context, args)

                    }, delay)

                }

            }



            let num = 0



            function scrollTap() {

                num++

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

            }

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

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

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

        }

    </script>

</body>



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



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



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





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

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

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

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

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



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

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



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



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



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

// 方法一:定時器實現(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)

    }

  }

}



// 方法二:時間戳

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

      }

  }

}



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



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

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




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





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



/*

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

 

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

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

 
@param  {boolean}  immediate   設(shè)置為ture時,調(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ā)時間間隔

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



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

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

            timeout = setTimeout(later, wait - last);

        } else {

            timeout = null;

            // 如果設(shè)定為immediate===true,因為開始邊界已經(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è)定延時

        if (!timeout) {

            timeout = setTimeout(later, wait);

        }

        if (callNow) {

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

            context = args = null;

        }



        return result;

    };

};



/*

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

 

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

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

 
@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í)行時間點

    let previous = 0;

    if (!options) options = {};

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

    let later = function() {

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

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

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

        let remaining = wait - (now - previous);

        context = this;

        args = _args;

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

    };

};


日歷

鏈接

個人資料

藍(lán)藍(lán)設(shè)計的小編 http://www.sdgs6788.com

存檔

嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片
<em id="09ttv"></em>
    <sup id="09ttv"><pre id="09ttv"></pre></sup>
    <dd id="09ttv"></dd>

        • 久久综合给合| 免费在线日韩av| 亚洲性图久久| 黄色成人在线网址| 一区二区激情视频| 六月婷婷久久| 亚洲欧美视频在线观看| 一区二区精品在线观看| 久久在线精品| 一区二区亚洲精品| 久久精品国产一区二区三区| 在线视频欧美日韩| 欧美激情国产日韩精品一区18| 国产一区视频在线看| 久久国产精品久久国产精品| 亚洲无线视频| 欧美性生交xxxxx久久久| 日韩午夜免费视频| 亚洲国产日日夜夜| 欧美在线观看天堂一区二区三区| 国产老女人精品毛片久久| 亚洲欧美综合另类中字| 欧美呦呦网站| 午夜电影亚洲| 国产在线观看一区| 国产欧美丝祙| 亚洲香蕉在线观看| 亚洲欧洲精品一区二区| 狠狠入ady亚洲精品| 国产精品三级视频| 在线视频亚洲欧美| 一区二区三区久久精品| 亚洲视频一区| 国产精品国产自产拍高清av王其| 亚洲专区国产精品| 亚洲免费在线| 激情综合在线| 最近看过的日韩成人| 欧美日韩国产成人在线观看| 亚洲影院色在线观看免费| 亚洲综合电影| 亚洲第一天堂av| 亚洲精品自在久久| 国产欧美日韩在线播放| 久久久国产午夜精品| 久久一区二区精品| 亚洲精品一区二区网址| 亚洲美女在线一区| 国产老肥熟一区二区三区| 另类春色校园亚洲| 欧美日韩成人在线| 久久精选视频| 欧美激情第二页| 久久精品国产99国产精品| 欧美xx视频| 欧美一区观看| 欧美r片在线| 午夜综合激情| 欧美国产精品va在线观看| 狠狠色丁香婷婷综合影院| 亚洲国产视频直播| 国产午夜精品理论片a级大结局| 一区二区三区国产在线| 免费在线成人av| 国产日韩av一区二区| 国产精品久久久久久久久久ktv| 亚洲女性喷水在线观看一区| 亚洲欧美韩国| 美女免费视频一区| 亚洲一区二区高清| 久久精品亚洲精品| 亚洲欧美另类在线| 欧美精品在线免费播放| 久久亚洲国产精品日日av夜夜| 欧美人妖在线观看| 免费视频一区二区三区在线观看| 欧美日韩国产页| 噜噜噜躁狠狠躁狠狠精品视频 | 久久一区二区三区av| 亚洲专区在线视频| 亚洲少妇最新在线视频| 亚洲国产精品t66y| 久久久久99| 久久国产66| 国产精自产拍久久久久久蜜| av成人国产| 日韩小视频在线观看| 免费人成网站在线观看欧美高清| 久久精品首页| 国产欧美亚洲一区| 久久精品天堂| 国产一区二区久久| 亚洲女与黑人做爰| 午夜国产精品视频免费体验区| 欧美国产三级| 亚洲电影欧美电影有声小说| 韩国在线一区| 久久精品国产精品亚洲| 久久久久久69| 韩国女主播一区| 久久丁香综合五月国产三级网站| 欧美在线观看视频在线| 国产欧美一二三区| 欧美亚洲综合久久| 久久久一本精品99久久精品66| 国内成+人亚洲| 欧美成人精精品一区二区频| 樱桃国产成人精品视频| 久久久久www| 欧美风情在线观看| 亚洲黄色精品| 欧美日产一区二区三区在线观看 | 99国产精品久久久| 欧美日韩国产精品一卡| 99视频一区二区| 国产欧美日韩在线播放| 欧美一级久久| 你懂的网址国产 欧美| 亚洲国产aⅴ天堂久久| 免费一级欧美片在线观看| 亚洲国产婷婷| 亚洲一区二区免费看| 国产精品免费在线| 亚洲第一精品夜夜躁人人躁 | 欧美一级理论片| 国产一区二区三区精品久久久| 久久精品国产亚洲一区二区| 亚洲高清久久网| 国产日产高清欧美一区二区三区| 久久久久**毛片大全| 日韩一级黄色av| 久久精品国产综合精品| 最近中文字幕日韩精品 | 国产主播喷水一区二区| 毛片av中文字幕一区二区| 夜夜爽www精品| 另类天堂视频在线观看| 在线视频日韩精品| 韩国av一区二区三区| 亚洲视频碰碰| 欧美11—12娇小xxxx| 亚洲视频福利| 精品二区久久| 国产精品免费在线 | 亚洲国产裸拍裸体视频在线观看乱了中文| 免费不卡亚洲欧美| 欧美一级电影久久| 日韩一级欧洲| 老色鬼精品视频在线观看播放| 艳妇臀荡乳欲伦亚洲一区| 国内成人精品视频| 国产精品高清免费在线观看| 老司机精品视频网站| 久久福利毛片| 国产精品99久久久久久宅男| 影音先锋另类| 国产午夜精品一区二区三区欧美 | 国产九色精品成人porny| 免费视频一区| 久久精品国产91精品亚洲| 亚洲天堂av电影| 亚洲激情精品| 欧美激情小视频| 久久久久久网站| 黄色国产精品| 国产视频一区在线| 国产精品久久福利| 欧美日韩国产一区二区三区地区| 久久精品国产99国产精品澳门| 亚洲视频一二三| 夜夜精品视频| 一区二区三区四区在线| 91久久综合亚洲鲁鲁五月天| 蜜桃av一区二区在线观看| 久久av在线看| 欧美中文字幕在线| 欧美一级淫片aaaaaaa视频| 亚洲私人影院| 亚洲欧美精品suv| 亚洲欧美成人一区二区在线电影| 一区二区三区视频在线观看| 日韩午夜三级在线| 亚洲手机在线| 国内在线观看一区二区三区| 国产日韩一区二区三区在线播放 | 久久精品国产v日韩v亚洲| 先锋影音网一区二区| 欧美一区二区高清在线观看| 午夜老司机精品| 中文精品视频一区二区在线观看| 一区二区三区.www| 亚洲精品视频在线看| 亚洲激情影院| 日韩视频中文| 亚洲视频在线看| 午夜在线观看免费一区| 嫩草国产精品入口| 亚洲激情在线观看| 亚洲精品一区二区三区四区高清| 日韩一级大片在线|