延遲加載(LazyLoading)三種實現(xiàn)方式

原文地址:延遲加載(LazyLoading)三種實現(xiàn)方式 轉(zhuǎn)載請注明出處

定義

延遲加載也稱為惰性加載懦底,即在長網(wǎng)頁中延遲加載圖像雅任。用戶滾動到它們之前吻谋,視口外的圖像不會加載忠蝗。這與圖像預(yù)加載相反,在長網(wǎng)頁上使用延遲加載將使網(wǎng)頁加載更快漓拾。在某些情況下,它還可以幫助減少服務(wù)器負(fù)載戒祠。

舉個例子來說明骇两,當(dāng)打開淘寶首頁的時候,只有在瀏覽器窗口里的圖片才會被加載姜盈,當(dāng)你滾動首頁向下滑的時候低千,進(jìn)入視口內(nèi)的圖片才會被加載,而其它從未進(jìn)入視口的圖像不會也不會加載馏颂。

那么延遲加載有什么好處

  1. 首先它能提升用戶的體驗示血,試想一下,如果打開頁面的時候就將頁面上所有的圖片全部獲取加載救拉,如果圖片數(shù)量較大难审,對于用戶來說簡直就是災(zāi)難,會出現(xiàn)卡頓現(xiàn)象亿絮,影響用戶體驗告喊。
  2. 有選擇性地請求圖片,這樣能明顯減少了服務(wù)器的壓力和流量派昧,也能夠減小瀏覽器的負(fù)擔(dān)黔姜。

那么下面就介紹延遲加載的三種實現(xiàn)方式:

第一種

首先將頁面上的圖片的 src 屬性設(shè)為 loading.gif,而圖片的真實路徑則設(shè)置在 data-src 屬性中蒂萎,頁面滾動的時候計算圖片的位置與滾動的位置秆吵,當(dāng)圖片出現(xiàn)在瀏覽器視口內(nèi)時,將圖片的 src 屬性設(shè)置為 data-src 的值五慈,這樣纳寂,就可以實現(xiàn)延遲加載主穗。

下面是具體的實現(xiàn)代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lazyload 1</title>
    <style>
        img {
        display: block;
        margin-bottom: 50px;
        height: 200px;
    }
    </style>
</head>
<body>
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    <script>
        function lazyload() {
        var images = document.getElementsByTagName('img');
        var len    = images.length;
        var n      = 0;      //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷       
        return function() {
        var seeHeight = document.documentElement.clientHeight;
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        for(var i = n; i < len; i++) {
            if(images[i].offsetTop < seeHeight + scrollTop) {
                if(images[i].getAttribute('src') === 'images/loading.gif') {
                 images[i].src = images[i].getAttribute('data-src');
            }
            n = n + 1;
             }
        }
        }
    }
    var loadImages = lazyload();
    loadImages();          //初始化首頁的頁面圖片
    window.addEventListener('scroll', loadImages, false);
    </script>
</body>
</html>

比較 image 的 offsetTop 與 seeHeight + scrollTop 的大小烈疚,當(dāng)小于時則說明圖片已經(jīng)出現(xiàn)過在視口中黔牵,這時候繼續(xù)判斷圖片是否已經(jīng)替換過,如果沒有替換過爷肝,則進(jìn)行替換猾浦。

實現(xiàn)的效果:不斷滑動頁面時,圖片延遲加載

你可以拷貝我的代碼去進(jìn)行實驗灯抛,但是請確保 HTML 同目錄下有 images 目錄并且含有 1~12.png 和 loading.gif金赦。

需要提及的是變量 n 是用來保存已經(jīng)加載的圖片數(shù)量,避免每次都從第一張圖片開始遍歷对嚼,提升性能夹抗。上面的代碼用到了 JS 閉包的知識,如果你不太熟悉的話纵竖,可以自行百度一下漠烧。

第二種

上面的代碼是沒什么問題,但是性能偏差靡砌。如果直接將函數(shù)綁定在 scroll 事件上,當(dāng)頁面滾動時通殃,函數(shù)會被高頻觸發(fā)度液,這非常影響瀏覽器的性能。我粗略地估計一下画舌,當(dāng)簡單地滾動一下頁面堕担,函數(shù)至少觸發(fā)了十來次,這顯然是十分沒必要的曲聂。
所以在做事件綁定的時候霹购,可以對 lazyload 函數(shù)進(jìn)行函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce)處理。
這里我并不再另外介紹這兩種方案句葵,如果你想了解的話可以閱讀:JS魔法堂:函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce) - _肥仔John - 博客園

簡單說來:

  • Debounce:一部電梯停在某一個樓層厕鹃,當(dāng)有一個人進(jìn)來后,20秒后自動關(guān)門乍丈,這20秒的等待期間剂碴,又一個人按了電梯進(jìn)來,這20秒又重新計算轻专,直到電梯關(guān)門那一刻才算是響應(yīng)了事件忆矛。
  • Throttle:好比一臺自動的飲料機(jī),按拿鐵按鈕,在出飲料的過程中催训,不管按多少這個按鈕洽议,都不會連續(xù)出飲料,中間按鈕的響應(yīng)會被忽略漫拭,必須要等這一杯的容量全部出完之后亚兄,再按拿鐵按鈕才會出下一杯。

下面就是經(jīng)過 throttle 處理后的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lazyload 2</title>
    <style>
    img {
        display: block;
        margin-bottom: 50px;
        height: 200px;
    }
    </style>
</head>
<body>
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    <script>
    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');
        var len    = images.length;
        var n      = 0;      //存儲圖片加載到的位置采驻,避免每次都從第一張圖片開始遍歷       
        return function() {
        var seeHeight = document.documentElement.clientHeight;
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        for(var i = n; i < len; i++) {
            if(images[i].offsetTop < seeHeight + scrollTop) {
                if(images[i].getAttribute('src') === 'images/loading.gif') {
                 images[i].src = images[i].getAttribute('data-src');
                }
            n = n + 1;
             }
        }
        }
    }
    var loadImages = lazyload();
    loadImages();          //初始化首頁的頁面圖片
    window.addEventListener('scroll', throttle(loadImages, 500, 1000), false);
    </script>
</body>
</html>

設(shè)置了 500ms 的延遲审胚,和 1000ms 的間隔,當(dāng)超過 1000ms 未觸發(fā)該函數(shù)礼旅,則立即執(zhí)行該函數(shù)膳叨,不然則延遲 500ms 執(zhí)行該函數(shù)。

實現(xiàn)效果:可以看出有一定的延遲痘系。

第三種

使用 IntersectionObserver API

目前有一個新的 IntersectionObserver API菲嘴,可以自動"觀察"元素是否可見,Chrome 51+ 已經(jīng)支持汰翠。

這里不過多介紹 IntersectionObserver API 的詳細(xì)使用龄坪,感興趣可以另外閱讀下面的文章:

Intersection Observer API 使用教程
Intersection Observer API

實現(xiàn)代碼:簡潔,但是瀏覽器尚未全部實現(xiàn)复唤。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lazyload 3</title>
    <style>
        img {
        display: block;
        margin-bottom: 50px;
        width: 800px;
        }
    </style>
</head>
<body>
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    ![](images/loading.gif)
    <script>
    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') == 'images/loading.gif') {
              target.src = target.getAttribute('data-src');
          }
        })
    });
    query('img').forEach(function(item) {
        io.observe(item);
    });
    </script>
</body>
</html>
  1. IntersectionObserver 傳入一個回調(diào)函數(shù)悉默,當(dāng)其觀察到元素集合出現(xiàn)時候,則會執(zhí)行該函數(shù)苟穆。
  2. io.observe 即要觀察的元素,要一個個添加才可以唱星。
  3. io 管理的是一個數(shù)組雳旅,當(dāng)元素出現(xiàn)或消失的時候,數(shù)組添加或刪除該元素间聊,并且執(zhí)行該回調(diào)函數(shù)攒盈。

參考文章

延遲加載三種實現(xiàn)方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哎榴,隨后出現(xiàn)的幾起案子型豁,更是在濱河造成了極大的恐慌,老刑警劉巖尚蝌,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迎变,死亡現(xiàn)場離奇詭異,居然都是意外死亡飘言,警方通過查閱死者的電腦和手機(jī)衣形,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姿鸿,“玉大人谆吴,你說我怎么就攤上這事倒源。” “怎么了句狼?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵笋熬,是天一觀的道長。 經(jīng)常有香客問我腻菇,道長胳螟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任芜繁,我火速辦了婚禮旺隙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骏令。我一直安慰自己蔬捷,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布榔袋。 她就那樣靜靜地躺著周拐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凰兑。 梳的紋絲不亂的頭發(fā)上妥粟,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音吏够,去河邊找鬼勾给。 笑死,一個胖子當(dāng)著我的面吹牛锅知,可吹牛的內(nèi)容都是我干的播急。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼售睹,長吁一口氣:“原來是場噩夢啊……” “哼桩警!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昌妹,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤捶枢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后飞崖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烂叔,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年蚜厉,在試婚紗的時候發(fā)現(xiàn)自己被綠了长已。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖术瓮,靈堂內(nèi)的尸體忽然破棺而出康聂,到底是詐尸還是另有隱情,我是刑警寧澤胞四,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布恬汁,位于F島的核電站,受9級特大地震影響辜伟,放射性物質(zhì)發(fā)生泄漏氓侧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一导狡、第九天 我趴在偏房一處隱蔽的房頂上張望约巷。 院中可真熱鬧,春花似錦旱捧、人聲如沸独郎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氓癌。三九已至,卻和暖如春贫橙,著一層夾襖步出監(jiān)牢的瞬間贪婉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工卢肃, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留疲迂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓莫湘,卻偏偏與公主長得像鬼譬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子逊脯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容