• <noscript id="ggggg"><dd id="ggggg"></dd></noscript>
    <small id="ggggg"></small> <sup id="ggggg"></sup>
    <noscript id="ggggg"><dd id="ggggg"></dd></noscript>
    <tfoot id="ggggg"></tfoot>
  • <nav id="ggggg"><cite id="ggggg"></cite></nav>
    <nav id="ggggg"></nav>
    成人黃色A片免费看三更小说,精品人妻av区波多野结衣,亚洲第一极品精品无码,欧美综合区自拍亚洲综合,久久99青青精品免费观看,中文字幕在线中字日韩 ,亚洲国产精品18久久久久久,黄色在线免费观看

    函數(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)用一次(僅僅只會調(diào)用一次!!!!!!!!!!)。



    舉個(gè)栗子:滾動(dòng)scroll事件,不停滑動(dòng)滾輪會連續(xù)觸發(fā)多次滾動(dòng)事件,從而調(diào)用綁定的回調(diào)函數(shù),我們希望當(dāng)我們停止?jié)L動(dòng)的時(shí),才觸發(fā)一次回調(diào),這時(shí)可以使用函數(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í)間間隔設(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í)間間隔會被調(diào)整到10毫秒。

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

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



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

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



    舉個(gè)栗子:還是以scroll滾動(dòng)事件來說吧,滾動(dòng)事件是及其消耗瀏覽器性能的,不停觸發(fā)。以我在項(xiàng)目中碰到的問題,移動(dòng)端通過scroll實(shí)現(xiàn)分頁,不斷滾動(dòng),我們不希望不斷發(fā)送請求,只有當(dāng)達(dá)到某個(gè)條件,比如,距離手機(jī)窗口底部150px才發(fā)送一個(gè)請求,接下來就是展示新頁面的請求,不停滾動(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ù)之前總會將timer用setTimeout清除,取消延遲代碼塊,確保只執(zhí)行一次

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




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





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



    /*

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

     

     
    @param  {function} func        傳入函數(shù),最后一個(gè)參數(shù)是額外增加的this對象,.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è)人資料

    存檔

    主站蜘蛛池模板: 老湿机看片新入口福利| 亚洲国产天堂久久国产91| 亚洲国产精品乱码一区二区| 精品国产一区二区三区免费看| 亚洲撸一撸| 中文字幕国产在线精品| 蜜臀亚洲精品国产aⅴ综合第一| 午夜短视频日韩免费| 日韩一区中文字幕在线| av在线播放观看地址| 国产午夜精品视频在线播放| 欧美性受xxxx喷水性欧洲| 91精品91久久久久久| 欧美 国产 人人视频| 国产999精品成人网站| 国产1区| 岛国在线无码高清视频| 亚洲一区二区三在线视频| 亚洲人成电影在线播放| 狠狠色噜噜狠狠狠7777米奇| 久久精品国产99精品国偷| 国产欧美综合在线观看第十页| 亚洲AV怡红院影院怡春院| 97色伦图区97色伦综合图区| 亚洲精品一卡2卡三卡4卡乱码天 | avの在线观看不卡| 国产一区丝袜在线播放| 999成人国产精品| AV边做边流奶水无码免费| 久久99精品中文字幕| 欧美成人免费观看国产| 亚洲一道一本快点视频| 免费观看精品视频999| 精品国产午夜理论片不卡| 嘉禾县| 日本精品久久久久中文字幕2 | 中字无码精油按摩中出视频| 99久热国产精品视频尤物| 特级毛片A级毛片免费播放| 亚洲中文字幕一区二区| 国产剧情无码播放在线看|