欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript優(yōu)化圖片懶加載的性能技巧

 更新時(shí)間:2024年06月13日 09:26:34   作者:睡著學(xué)  
前端發(fā)展過程中有許多性能優(yōu)化的操作,比如防抖、節(jié)流和圖片懶加載等,在這里我們首先聊聊圖片懶加載操作,我們會經(jīng)常逛像淘寶和京東等購物平臺,一次性全部加載會導(dǎo)致加載時(shí)間長、網(wǎng)絡(luò)資源消耗大,所以本文給大家介紹了JavaScript優(yōu)化圖片懶加載的性能技巧

背景

前端發(fā)展過程中有許多性能優(yōu)化的操作,比如防抖、節(jié)流和圖片懶加載等。在這里我們首先聊聊圖片懶加載操作。

在最近的618中,我們會經(jīng)常逛像淘寶和京東等購物平臺。那你覺得在淘寶頁面中的圖片資源是打開頁面時(shí)就一次性全部加載完了呢,還是在你滾輪滾動到的區(qū)域才加載圖片呢。

一次性全部加載會導(dǎo)致加載時(shí)間長、網(wǎng)絡(luò)資源消耗大、內(nèi)存占用率高和發(fā)出大量圖片請求給服務(wù)器帶來的巨大壓力。

所以采用的是只加載當(dāng)前可見區(qū)域的圖片,隨著用戶的滾動,當(dāng)其他圖片進(jìn)入可見區(qū)域時(shí),再進(jìn)行加載。這種方法就是圖片的懶加載。這種方式可以有效地提高頁面的響應(yīng)速度,特別是在圖片數(shù)量較多或網(wǎng)絡(luò)條件較差的情況下,可以避免頁面加載緩慢或卡頓的現(xiàn)象,提供更好的用戶體驗(yàn)。

如下圖所示,淘寶頁面剛打開時(shí)并不是全部加載的。

大致思路

圖片懶加載布局邏輯:

  • 通過將img標(biāo)簽的src屬性值都設(shè)置為同一個(gè)圖片的url,這個(gè)圖片需要盡可能小。這樣即可以為后續(xù)要真正加載的圖片占位置,也可以讓頁面布局更快地呈現(xiàn)出來,而不是長時(shí)間等待圖片加載導(dǎo)致空白。
  • 將每一個(gè)img標(biāo)簽中真正的圖片url存放在一個(gè)數(shù)據(jù)屬性當(dāng)中。當(dāng)需要加載時(shí)將該數(shù)據(jù)屬性內(nèi)的內(nèi)容賦值給img標(biāo)簽的src屬性。

圖片懶加載交互邏輯:

  • 首先通過獲取用戶可視窗口高度、滾輪到最頂端的距離和每個(gè)圖片到最頂端的距離。
  • 通過監(jiān)聽器監(jiān)聽滾輪滾動事件觸發(fā)懶加載函數(shù)。
  • 但是一開始就出現(xiàn)在可視窗口的圖片需要直接加載,所以需要先運(yùn)行一次懶加載函數(shù)。
  • 在懶加載函數(shù)里通過判斷(圖片到最頂端的距離)和(用戶可視窗口高度+滾輪到最頂端的距離)的大小判斷是否需要加載。

編輯代碼

html部分

<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/hsossms/20240612/v2_8ec7812750194dbd831babce8806c626@000000_oswg5522709oswg1792oswg1024_img_png?x-oss-process=image/resize,m_mfit,w_600,h_400,limit_0/crop,w_600,h_400,g_center/format,webp" />
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190808/v2_1565254363234_img_jpg">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567641293753_img_png">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567640518658_img_png">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567642423719_img_000">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567642425030_img_000">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567642425101_img_000">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567642425061_img_000">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190904/v2_1567591358070_img_jpg">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000">
<img src="https://misc.360buyimg.com/mtd/pc/common/img/blank.png"
     data-src="https://img.36krcdn.com/20190905/v2_1567641974454_img_000">

在html部分中有一個(gè)重要的步驟。你會發(fā)現(xiàn)每一個(gè)img標(biāo)簽的src屬性值都是一樣的,我們可以復(fù)制鏈接到瀏覽器查看該圖片。

該圖片是中間的小白點(diǎn):

該圖片的屬性如下:

可以看出這個(gè)圖片是非常小的。在頁面打開時(shí),加載的都是這個(gè)圖片,真正要加載的圖片url放置在data-src數(shù)據(jù)屬性里面。最后通過JavaScript部分實(shí)現(xiàn)將data-src數(shù)據(jù)屬性的內(nèi)容賦值給img標(biāo)簽的src屬性,然后發(fā)送HTTP請求加載真正的圖片。

css部分

img {
    display: block;
    margin-bottom: 50px;
    width: 400px;
    height: 400px;
}

body {
    background-color: gray;
}

通過設(shè)置img 標(biāo)簽樣式,讓小圖片給真正要放的圖片占位置。

JavaScript部分

  • 變量定義:其中imgs是包含頁面中所有<img>元素的集合,可以通過索引來訪問具體的圖像元素;num表示圖片數(shù)量;n記錄被加載的圖片數(shù)量。
const imgs = document.getElementsByTagName('img');
const num = imgs.length;
let n = 0
  • 在全局一個(gè)設(shè)置scroll事件監(jiān)聽器,當(dāng)事件觸發(fā)后會調(diào)用lazyload慢加載函數(shù)。
window.addEventListener('scroll', lazyload)
  • 定義一個(gè)lazyload慢加載函數(shù):
function lazyload() {
    //可視區(qū)域的高度
    let screenHeight = document.documentElement.clientHeight;
    //滾動條距離最頂部的距離,
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    //判斷圖片是否存在在可視區(qū)域內(nèi)
    for (let i = n; i < num; i++) {
        if (imgs[i].offsetTop > scrollTop + screenHeight) {
            break;
        } else {
            //主動觸發(fā)下載
            imgs[i].src = imgs[i].getAttribute('data-src');
            //記錄已經(jīng)加載過的圖片數(shù)量
            n = i + 1;
            if (n === num) {
                //全部加載完畢后移除滾動事件
                window.removeEventListener('scroll', lazyload);
            }
        }
    }
}
  • 首先獲取可視窗口的高度screenHeight、滾動條距離最頂部的距離scrollTop和具體圖片距離最頂端的距離imgs[i].offsetTop。通過for循環(huán)遍歷每個(gè)img元素。

    • 當(dāng)imgs[i].offsetTop > scrollTop + screenHeight時(shí),也就是說該圖片的區(qū)域并沒有被可視區(qū)域覆蓋過,所以圖片不需要加載,也就沒有別的后續(xù)操作了。
    • 如果imgs[i].offsetTop <= scrollTop + screenHeight時(shí),說明該圖片的區(qū)域被可視區(qū)域覆蓋了,圖片需要進(jìn)行加載。
  • 當(dāng)圖片需要加載時(shí),將真正的圖片url賦值給src屬性。由imgs[i].src = imgs[i].getAttribute('data-src')實(shí)現(xiàn)。

  • 每次加載一張圖片n的值就加一。當(dāng)n的值等于num的值時(shí),也就是所有圖片都加載完成后就不需要scroll事件監(jiān)聽器了,所有通過window.removeEventListener('scroll', lazyload)清除監(jiān)聽器。

  • 最后因?yàn)槭灼羶?nèi)的圖片需要直接加載,而不是通過scroll事件監(jiān)聽器實(shí)現(xiàn)加載。所有需要調(diào)用一次慢加載函數(shù)。

//方法一
document.addEventListener('DOMContentLoaded', lazyload)
//方法二
window.addEventListener('load', lazyload)
  • 方法一通過DOMContentLoaded事件監(jiān)聽器觸發(fā)慢加載函數(shù)的速度比方法二通過load事件監(jiān)聽器觸發(fā)慢加載函數(shù)的速度快。所以推薦方法一。

節(jié)流優(yōu)化

因?yàn)?code>scroll事件監(jiān)聽器在頻繁的滑輪滾動會頻繁觸發(fā)。如果直接在事件處理函數(shù)中執(zhí)行大量復(fù)雜的操作,可能會導(dǎo)致性能問題。

所以通過使用節(jié)流限制事件觸發(fā)的頻率。

const imgs = document.getElementsByTagName('img');
const num = imgs.length;
//用變量記錄節(jié)流返回的函數(shù)
const throttleLazyLoad = throttle(lazyload, 200);
//滾動事件觸發(fā)懶加載
window.addEventListener('scroll', throttleLazyLoad)
let n = 0
//首屏加載,DOMContentLoaded事件是DOM加載完成,不包括圖片(比load事件快)
document.addEventListener('DOMContentLoaded', lazyload)
//首屏加載,load事件是DOM加載完成,包括圖片(比DOMContentLoaded事件慢)
window.addEventListener('load', lazyload)
//懶加載函數(shù)
function lazyload(event) {
    //可視區(qū)域的高度
    let screenHeight = document.documentElement.clientHeight;
    //滾動條距離最頂部的距離,
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    //判斷圖片是否存在在可視區(qū)域內(nèi)
    for (let i = n; i < num; i++) {
        if (imgs[i].offsetTop > scrollTop + screenHeight) {
            break;
        } else {
            //主動觸發(fā)下載
            imgs[i].src = imgs[i].getAttribute('data-src');
            //記錄已經(jīng)加載過的圖片數(shù)量
            n = i + 1;
            if (n === num) {
                //全部加載完畢后移除滾動事件
                window.removeEventListener('scroll', throttleLazyLoad);
            }
        }
    }
}
//節(jié)流函數(shù)
function throttle(func, limit) {
    let inThrottle;
    return function () {
        const context = this;
        const args = arguments;
        if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

定義了一個(gè)節(jié)流函數(shù),它接收要執(zhí)行的函數(shù) func 和時(shí)間間隔限制 limit。內(nèi)部通過一個(gè)變量 inThrottle 來標(biāo)記當(dāng)前是否處于節(jié)流狀態(tài)。當(dāng)執(zhí)行返回的函數(shù)時(shí),先判斷如果不在節(jié)流狀態(tài),就立即執(zhí)行目標(biāo)函數(shù),并將 inThrottle 設(shè)置為 true,同時(shí)使用 setTimeout 在指定時(shí)間間隔后將 inThrottle 恢復(fù)為 false,從而實(shí)現(xiàn)了在規(guī)定時(shí)間間隔內(nèi)只執(zhí)行一次函數(shù)的節(jié)流效果,避免了頻繁觸發(fā)導(dǎo)致的性能問題。

再次優(yōu)化

在日常工作時(shí),如果讓你選擇手搓一個(gè)節(jié)流函數(shù)和直接使用工具庫里的函數(shù),你肯定也會和我一樣偷懶,選擇直接使用工具庫里的現(xiàn)成的函數(shù)。

首先在HTML中使用以下代碼引入 Lodash 庫。

<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

然后可以刪除掉你手搓的節(jié)流函數(shù)了,使用 Lodash 庫里的節(jié)流函數(shù)。

const imgs = document.getElementsByTagName('img');
const num = imgs.length;
//用變量記錄節(jié)流返回的函數(shù)
const throttleLazyLoad = _.throttle(lazyload, 200);//調(diào)用Lodash庫里的節(jié)流函數(shù)
//滾動事件觸發(fā)懶加載
window.addEventListener('scroll', throttleLazyLoad)
let n = 0
//首屏加載,DOMContentLoaded事件是DOM加載完成,不包括圖片(比load事件快)
document.addEventListener('DOMContentLoaded', lazyload)
//首屏加載,load事件是DOM加載完成,包括圖片(比DOMContentLoaded事件慢)
window.addEventListener('load', lazyload)
//懶加載函數(shù)
function lazyload(event) {
    //可視區(qū)域的高度
    let screenHeight = document.documentElement.clientHeight;
    //滾動條距離最頂部的距離,
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    //判斷圖片是否存在在可視區(qū)域內(nèi)
    for (let i = n; i < num; i++) {
        if (imgs[i].offsetTop > scrollTop + screenHeight) {
            break;
        } else {
            //主動觸發(fā)下載
            imgs[i].src = imgs[i].getAttribute('data-src');
            //記錄已經(jīng)加載過的圖片數(shù)量
            n = i + 1;
            if (n === num) {
                //全部加載完畢后移除滾動事件
                window.removeEventListener('scroll', throttleLazyLoad);
            }
        }
    }
}

呈現(xiàn)效果

當(dāng)所有圖片加載完后滾動事件就不會觸發(fā)慢加載函數(shù)了,并且也有節(jié)流效果。

首屏的圖片立即加載,區(qū)域圖片在滾動到再加載。

以上就是JavaScript優(yōu)化圖片懶加載的性能技巧的詳細(xì)內(nèi)容,更多關(guān)于JavaScript優(yōu)化圖片懶加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論