<strike id="g3zqm"></strike>

      <cite id="g3zqm"></cite>

        <tr id="g3zqm"><center id="g3zqm"></center></tr>
        <pre id="g3zqm"><sup id="g3zqm"></sup></pre>
        <li id="g3zqm"></li>
      1. 少妇高潮激情一区二区三,免费av深夜在线观看,亚洲狼人久久伊人久久伊,久久精品人人做人人爽电影蜜月,黄色特级片一区二区三区,欧美日韩在线亚洲二区综二,极品少妇无套内射视频,日本极品少妇videossexhd

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

        2020-4-29    seo達人

        函數(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ù),我們希望當我們停止?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ā)時間間隔設置的很小

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

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

                }

            </script>

        </body>



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



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



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





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

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

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

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

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



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

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



        舉個栗子:還是以scroll滾動事件來說吧,滾動事件是及其消耗瀏覽器性能的,不停觸發(fā)。以我在項目中碰到的問題,移動端通過scroll實現(xiàn)分頁,不斷滾動,我們不希望不斷發(fā)送請求,只有當達到某個條件,比如,距離手機窗口底部150px才發(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頁面中進行測試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無法傳遞進函數(shù)

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

         
        @param  {boolean}  immediate   設置為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小于設定時間間隔wait

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

                    timeout = setTimeout(later, wait - last);

                } else {

                    timeout = null;

                    // 如果設定為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;

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

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

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

                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í)行不存在,且沒有設定結(jié)尾邊界不執(zhí)行選項

                } else if (!timeout && options.trailing !== false) {

                    timeout = setTimeout(later, remaining);

                }

                return result;

            };

        };


        日歷

        鏈接

        個人資料

        藍藍設計的小編 http://m.hengshangtqd.cn

        存檔

        主站蜘蛛池模板: 国产香蕉国产精品偷在线观看| 动漫AV纯肉无码AV电影网| 99久久国产综合精品1| 亚洲 欧美 中文 日韩天堂| 在线涩涩免费观看国产精品| 377P欧洲日本亚洲大胆| 人妻中文字幕亚洲精品| 影音先锋自拍| 海盐县| 一本久久a久久精品vr综合| 成人国产精品中文字幕| 日本一区二区三区免费播放视频站| japanese边做边乳喷| 午夜男女很黄的视频| 天天干天天日三级| 在线无码视频观看草草视频| 精品亚洲国产亚洲国产| 无码av不卡免费播放| 中文字幕日韩一区二区三区不卡| 国产精品夜夜爽7777777| 亚洲av无码牛牛影视在线二区| 人妻少妇伦在线无码专区视频| 无码AV最新无码AV专区| 丰满熟妇人妻av无码区| 四虎永久在线精品免费看| 91导航| 影音av资源| 福清市| 国产精品无码一区二区在线| 色综合天天综合高清网国产在线 | 人妻无码中文字幕免费视频蜜桃 | 欧美性猛交xxxx乱大交极品| 国产一区二区精品偷系列| 99国产精成人午夜视频一区二区| 噜噜涩99| 亚洲 欧美 变态 卡通 自拍| 国产av一区二区不卡| 国产精品无码久久久久AV| 日韩精品一二三四五区| 在线免费不卡视频| 野花韩国高清电影|