防抖、節流 和 預加載、懶加載

目錄

1. 防抖 節流

2. 預加載

3. 懶加載

(一)防抖 節流

1. 防抖

對於短時間內連續觸發的事件(如滾動事件),防抖的含義就是讓某個時間期限(如上面的1000毫秒)內,事件處理函數只執行一次。

防抖實現思路:在第一次觸發事件時,不立即執行函數,而是給出一個期限值比如200ms,然後:

  • 如果在200ms內沒有再次觸發滾動事件,那麼就執行函數
  • 如果在200ms內再次觸發滾動事件,那麼當前的計時取消,重新開始計時

效果:如果短時間內大量觸發同一事件,只會執行一次函數。

實現:既然前面都提到了計時,那實現的關鍵就在於setTimeOut這個函數,由於還需要一個變量來保存計時,考慮維護全局純淨,可以藉助閉包來實現:

/*
* fn [function] 需要防抖的函數
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn, delay) {
    let timer = null;
	return function() {
        if (timer) {
            claerTimeout(timer)
        }
        timer = setTimeout(fn, delay)
    }
}

2. 節流

效果:如果短時間內大量觸發同一事件,那麼在函數執行一次之後,該函數在指定的時間期限內不再工作,直至過了這段時間才重新生效

function throttle(fn, delay) {
    let valid = true;
    return function() {
        if (!valid) { //valid = false,休息時間,不執行
            return false
        }
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}

(二)預加載

1. 什麼是預加載?

圖片等靜態資源在使用前提前請求,資源後續使用可以直接從緩存中加載。

2. 爲什麼使用預加載?

在網頁全部加載之前,對一些主要內容進行加載,以提供給用戶更好的體驗,減少等待的時間。否則,如果一個頁面的內容過於龐大,沒有使用預加載技術的頁面就會長時間的展現爲一片空白,直到所有內容加載完畢。但預加載會增加服務器的負擔。

3. 實現預加載的方法

  • 單純的js預加載圖片

                var images = new Array()  
                function preload() {  
                    for (let i = 0; i < preload.arguments.length; i++) {  
                        images[i] = new Image()  
                        images[i].src = preload.arguments[i]  
                    }  
                }  
                preload(  
                    "http://domain.tld/gallery/image-001.jpg",  
                    "http://domain.tld/gallery/image-002.jpg",  
                    "http://domain.tld/gallery/image-003.jpg"  
                )  
    
  • 使用ajax實現預加載

    window.onload = function() {  
        setTimeout(function() {  
            // XHR to request a JS and a CSS  
            var xhr = new XMLHttpRequest();  
            xhr.open('GET', 'http://domain.tld/preload.js');  
            xhr.send('');  
            xhr = new XMLHttpRequest();  
            xhr.open('GET', 'http://domain.tld/preload.css');  
            xhr.send('');  
            // preload image  
            new Image().src = "http://domain.tld/preload.png";  
        }, 1000);  
    };
    

(三)懶加載

1. 什麼是懶加載?

懶加載也就是延遲加載。簡單的來說,只有當圖片出現在瀏覽器的可視區域內時,才設置圖片正真的路徑,讓圖片顯示出來。

2. 爲什麼使用懶加載?

對於圖片過多的場景,爲了提高頁面的加載速度,很多時候我們需要將頁面內未出現在可視區域內的圖片先不做加載, 等到滾動到可視區域後再去加載。這樣子對於頁面加載性能上會有很大的提升,也提高了用戶體驗。

懶加載的主要目的是作爲服務器前端的優化,降低服務器的負載,減少請求數或延遲請求數。

3. 懶加載原理

將頁面中的img標籤src指向一張小圖片或者src爲空,然後自定義data-src屬性指向真實的圖片。當載入頁面時,先把可視區域內的img標籤的data-src屬性值賦給src,然後監聽滾動事件,把用戶即將看到的圖片加載。這樣便實現了懶加載。

加載條件:

img.offsetTop < window.innerHeight + document.body.scrollTop;

關於頁面寬高的資料

頁面高度詳解

scrollTop等元素距離

理清window和document的區別以及兩者的寬高
在這裏插入圖片描述

4. 實現

學習並摘自實現圖片懶加載(lazyload)

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        img {
            display: block;
            margin-bottom: 50px;
            width: 400px;
            height: 400px;
        }
    </style>
</head>
<body>
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
    <img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
    <img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
</body>

JavaScript

<!-- 純js -->
<script>
    var imgs = document.getElementsByTagName("img");
    var num = imgs.length;
    var n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷

    lazyload(); //頁面載入完畢加載可是區域內的圖片

    window.onscroll = lazyload;

    function lazyload() { //監聽頁面滾動事件
        var seeHeight = document.documentElement.clientHeight; //可見區域高度
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滾動條距離頂部高度
        for (var i = n; i < num; i++) {
            if (imgs[i].offsetTop < seeHeight + scrollTop) {
                if (imgs[i].getAttribute("src") == "default.jpg") {
                    imgs[i].src = imgs[i].getAttribute("data-src");
                }
                n = i + 1;
            }
        }
    }
</script>

JQuery

<script>
    var n = 0,
        imgNum = $("img").length,
        img = $('img');

    lazyload();

    $(window).scroll(lazyload);

    function lazyload(event) {
        for (var i = n; i < imgNum; i++) {
            if (img.eq(i).offset().top < parseInt($(window).height()) + parseInt($(window).scrollTop())) {
                if (img.eq(i).attr("src") == "default.jpg") {
                    var src = img.eq(i).attr("data-src");
                    img.eq(i).attr("src", src);

                    n = i + 1;
                }
            }
        }
    }
</script>

如果直接將函數綁定在scroll事件上,當頁面滾動時,函數會被高頻觸發,這非常影響瀏覽器的性能。

下面實現限制觸發頻率,來優化性能。

使用節流函數進行性能優化

// 簡單的節流函數
//fun 要執行的函數
//delay 延遲
//time  在time時間內必須執行一次
function throttle (fun, delay, time) {
  let timeout

  let startTime = new Date()

  return function () {
    let context = this

    let args = Array.prototype.slice.call(arguments)

    let curTime = new Date()

    clearTimeout(timeout)
    if (curTime - startTime >= time) {
      // 如果達到了規定的觸發時間間隔,觸發 handler
      fun.apply(context, args)
      startTime = curTime
    } else {
      // 沒達到觸發間隔,重新設定定時器
      timeout = setTimeout(function () {
        fun.apply(context, args)
      }, delay)
    }
  }
};
// 實際想綁定在 scroll 事件上的 handler
function lazyload(event) {}
// 採用了節流函數
window.addEventListener('scroll',throttle(lazyload,500,1000));

使用防抖函數進行性能優化

防抖相比較節流函數要稍微簡單一點,防抖是讓函數延遲執行,而節流比防抖多了一個在一定時間內必須要執行一次。

// debounce函數用來包裹我們的事件
function debounce (fn, delay) {
  // 持久化一個定時器 timer
  let timer = null
  // 閉包函數可以訪問 timer
  return function () {
    // 通過 'this' 和 'arguments'
    // 獲得函數的作用域和參數
    let context = this
    let args = Array.prototype.slice.call(arguments)
    // 如果事件被觸發,清除 timer 並重新開始計時
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}

// 實際想綁定在 scroll 事件上的 handler
function lazyload(event) {}
// 採用了去抖函數
window.addEventListener('scroll',debounce(lazyload,500));
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章