原文連接 - https://zhuanlan.zhihu.com/p/25455672javascript
延遲加載也稱爲惰性加載,即在長網頁中延遲加載圖像。
用戶滾動到它們以前,視口外的圖像不會加載。
這與圖像預加載相反,在長網頁上使用延遲加載將使網頁加載更快。
在某些狀況下,它還能夠幫助減小服務器負載。css
延遲加載的優勢:html
提高用戶的體驗,若是圖片數量較大,打開頁面的時候要將將頁面上全部的圖片所有獲取加載,極可能會出現卡頓現象,影響用戶體驗。所以,有選擇性地請求圖片,這樣能明顯減小了服務器的壓力和流量,也可以減少瀏覽器的負擔。java
將頁面上全部圖片的src
屬性設置爲loading.gif
,而圖片的真實路徑則設置在data-src
屬性中。api
當頁面滾動的時候計算圖片位置和滾動的位置,當圖片出如今瀏覽器視口內時,將圖片的src
屬性設置爲data-src
的值。數組
<img src="loading.png" data-src="image.png">
img { display: block; margin-bottom: 50px; }
function lazyload() { var images = document.getElementsByTagName('img'); var n = 0; // 用於存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷 return function() { var seeHeight = document.documentElement.clientHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(var i = n; i < images.length; i++) { if (images[i].offsetTop < seeHeight + scrollTop) { if (images[i].getAttribute('src') === 'loading.png') { images[i].src = images[i].getAttribute('data-src'); } n = n + 1; } } } } lazyload(); //初始化首頁的頁面圖片 window.addEventListener('scroll', lazyload(), false);
上面的方法雖然沒什麼問題,可是性能較差,由於當頁面滾動時,scroll
事件會高頻觸發,這很是影響瀏覽器性能。
因此,這裏要對lazyload
函數進行函數節流(throttle)與函數去抖(debounce)處理。瀏覽器
函數節流(throttle)與函數去抖(debounce)服務器
這裏html和css代碼不變,通過throttle處理的js代碼以下:函數
function throttle (fn, delay, atleast) { var timeout = null, startTime = new Date(); return function () { var curTime = new Date(); clearTimeout(timeout); if (curTime - startTime >= atleast) { fn (); startTime = curTime; } else { timeout = setTimeout (fn, delay); } } } function lazyload() { var images = document.getElementsByTagName('img'), n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷 return function() { var seeHeight = document.documentElement.clientHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(var i = n; i < images.length; i++) { if(images[i].offsetTop < seeHeight + scrollTop) { if(images[i].getAttribute('src') === 'loading.png') { images[i].src = images[i].getAttribute('data-src'); } n = n + 1; } } } } lazyload(); //初始化首頁的頁面圖片 window.addEventListener('scroll', throttle(lazyload(), 500, 1000), false);
目前有一個新的 IntersectionObserver API,能夠自動"觀察"元素是否可見。性能
用這種方法實現代碼很是簡潔,可是許多瀏覽器不支持。
IntersectionObserver 傳入一個回調函數,當其觀察到元素集合出現時候,則會執行該函數。
io.observe 即要觀察的元素,要一個個添加才能夠。
io 管理的是一個數組,當元素出現或消失的時候,數組添加或刪除該元素,而且執行該回調函數。
function query(selector) { return Array.from(document.querySelectorAll(selector)); } var io = new IntersectionObserver(function(items) { items.forEach(function(item) { var target = item.target; if(target.getAttribute('src') == 'loading.png') { target.src = target.getAttribute('data-src'); } }) }); query('img').forEach(function(item) { io.observe(item); });