国产精品爱久久久久久久小说,女人扒开腿让男人桶到爽 ,亚洲欧美国产双大乳头,国产成人精品综合久久久久,国产精品制服丝袜无码,免费无码精品黄av电影,黑色丝袜无码中中文字幕,乱熟女高潮一区二区在线

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

            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.dzxscac.cn

            存檔

            主站蜘蛛池模板: 色八区人妻在线视频免费| 无码一区中文字幕| a∨在线视频播放| 国产精品一品二品| 怡红院一区二区三区在线| 亚洲卡1卡2卡3精品| www.色综合| 国产女主播一区| 九九久久精品无码专区| 狠狠噜天天噜日日噜色综合 | 国产揄拍国产精品人妻蜜| 一本到av| 久久奇米| 亚洲一区二区三区成人网站| 国产精品麻豆成人av电影| 欧美黄色一级生活片| 免费超爽大片黄| 免费午夜无码视频在线观看| 国产精品视频第一页| 成人看的毛片| 视频一区国产第一页| 一级片免费在线观看| www.99爱| 丁香五香天堂网| 小辣椒福利视频精品导航| 三级国产视频| 青青在线视频一区二区三区| 国产成人亚洲精品无码不卡| 久热爱精品视频在线◇| 久久深夜福利| 欧洲美熟女乱又伦av影片| 久久精品国产亚洲a∨麻豆| 秋霞国产午夜精品免费视频| 国产东北真实交换多p免视频| 国产女人爽的流水毛片| 久久久久久久久久久综合日本| 性欧美ⅴideo另类hd| 国产精品人人爽人人做我的可爱| 免费人妻无码不卡中文18禁| 免费不卡视频| 成人乱码一区二区三区|