自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何在網(wǎng)頁上高效渲染 1000 萬張小圖片的?

開發(fā) 前端
從最初的逐個加載小圖片,到探索 Canvas,再到通過圖片塊合并優(yōu)化加載效率,每一步都是在不斷優(yōu)化用戶體驗與性能之間的平衡。

最近,看到一個名為 10MPage.com 的網(wǎng)站,目標是記錄 2025 年互聯(lián)網(wǎng)的時代印記。每個用戶都可以上傳一張 64x64 像素的小圖片,形成一個龐大的互聯(lián)網(wǎng)影像檔案。

正如名字所暗示的,這個頁面需要承載高達 1000 萬張小圖片。剛開始想到這個概念時,心想如何高效渲染這些圖片?。在本文中,我將分享作者嘗試的各種方案,以及最終實現(xiàn)的高效解決方案。

在你繼續(xù)閱讀之前,可以先訪問一下 10MPage.com 看看能不能猜到我是如何實現(xiàn)的。如果你已經(jīng)打開了10MPage,不妨也為自己上傳一張圖片,搶占一個位置吧!??

HTML <img> 標簽 vs Canvas

首先面臨的選擇是:用傳統(tǒng)的 HTML 元素來渲染,還是用 Canvas 來進行繪制。

方法一:大量單獨的 <img> 標簽

我最初使用了單獨的 <img> 標簽分別加載圖片。我寫了一個腳本,生成一個32x32(共1024張圖片)的圖片網(wǎng)格,用 Laravel Blade 模板進行渲染:

<div class="grid" id="grid">
    @for($y = 0; $y < 32; $y++)
        <div class="row">
            @for($x = 0; $x < 32; $x++)
                <div class="tile">
                    <img src="http://10mpage.test/tiles/{{$y}}x{{$x}}.png" alt="Tile {{$y}}x{{$x}}">
                </div>
            @endfor
        </div>
    @endfor
</div>

對應的 CSS 樣式:

body {
    margin: 0;
    padding: 0;
    overflow: auto; /* 允許滾動 */
}

.grid {
    display: block;
    position: relative;
    width: 100%; 
}

.row {
    display: flex;
}

.tile {
    width: 64px;
    height: 64px;
    box-sizing: border-box;
    border: 1px solid #ccc;
}

.tile img {
    width: 64px;
    height: 64px;
    object-fit: cover;
}

這種方式初步看起來不錯,但潛藏幾個嚴重問題:

  • 瀏覽器滾動性能差
  • DOM 節(jié)點數(shù)量龐大,性能開銷大
  • 大量圖片同時加載,網(wǎng)絡請求數(shù)激增
  • 難以實現(xiàn)平滑滾動或高級動畫效果

方法二:Canvas 繪制圖片

于是嘗試了 Canvas 方式。首先,通過繪制一個棋盤格圖案來測試 Canvas 渲染效率:

// 簡化的棋盤格Canvas繪制代碼示意:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const tileSize = 64;
let translateX = 0, translateY = 0, scale = 1;

// 繪制棋盤格
function drawGrid() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(translateX, translateY);
    ctx.scale(scale, scale);

    const cols = Math.ceil(canvas.width / (tileSize * scale)) + 2;
    const rows = Math.ceil(canvas.height / (tileSize * scale)) + 2;

    for (let x = 0; x < cols; x++) {
        for (let y = 0; y < rows; y++) {
            ctx.fillStyle = (x + y) % 2 ? '#fff' : '#000';
            ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
        }
    }

    ctx.restore();
}
drawGrid();

Canvas 方式優(yōu)勢顯著:

  • 靈活的滾動和縮放功能
  • 極大減少 DOM 節(jié)點
  • 性能優(yōu)秀,支持高級動畫和交互效果

經(jīng)過對比后,我最終選擇了 Canvas 方式,它提供了更大的靈活性和更好的渲染效率。

如何優(yōu)化圖片加載效率?

雖然 Canvas 的性能不錯,但加載數(shù)百萬張小圖片仍然存在巨大挑戰(zhàn)。假設以一個標準的 1080p 屏幕為例:

  • 寬度:1920px / 64px ≈ 30 張圖片
  • 高度:1080px / 64px ≈ 17 張圖片
  • 共需渲染 30 × 17 = 510 張圖片。

為了實現(xiàn)流暢滾動,頁面還需提前預加載周圍的圖片。如果將屏幕外 8 個方向的圖片也加載,意味著一次滾動需要加載 4080 張圖片,這幾乎是不可能瞬間加載完畢的。

解決方案:合并小圖片到大圖塊。

將小圖片合并成大圖塊

為解決單獨圖片加載產(chǎn)生的網(wǎng)絡請求過多的問題,設計了一個后端 PHP 控制器,將 16 × 16(256張) 小圖片合并成一個大的圖片塊(每個塊1024×1024像素)。

用戶訪問頁面時,瀏覽器將僅需加載較少數(shù)量的大圖塊,而非大量單獨圖片。這極大地減少了網(wǎng)絡請求次數(shù),提升加載速度。

例如上面的例子,現(xiàn)在只需加載 24 張 大圖塊,而非4080張單獨圖片:

  • 寬度:5760px / 1024px ≈ 6 張
  • 高度:3240px / 1024px ≈ 4 張
  • 6 × 4 = 24 張圖片,負載完全可控!

未上傳圖片的位置顯示為“?”號,清晰表示未填充。

一些提升用戶體驗的小技巧

為了更好地隱藏大圖塊加載細節(jié),提升用戶體驗,作者采用了一些小技巧:

  • 加載動畫始終顯示為 64×64 的小塊,使用戶感知不到是加載了更大的圖片塊。
  • 網(wǎng)格總是方形加載,避免出現(xiàn)邊界空白的視覺問題。

經(jīng)驗與總結

回顧整個過程,從最初的逐個加載小圖片,到探索 Canvas,再到通過圖片塊合并優(yōu)化加載效率,每一步都是在不斷優(yōu)化用戶體驗與性能之間的平衡。

責任編輯:姜華 來源: 大遷世界
相關推薦

2021-12-20 07:58:59

GitHub源碼代碼

2017-05-09 09:36:52

Android App高效顯示位圖

2015-01-07 09:11:49

惡意IPipset阻止惡意IP

2013-05-22 09:59:10

HTML 5音頻

2012-08-27 10:32:12

2018-03-25 08:44:07

iPhonePDF網(wǎng)頁

2014-06-26 16:05:53

2014-06-27 14:36:03

iOS演示APP原型

2020-11-16 08:07:51

瀏覽器渲染網(wǎng)頁

2018-09-17 14:06:46

UCloudUGC

2018-09-17 13:52:39

UCloudUGC

2018-09-17 14:02:28

UCloudGUC

2012-12-10 09:49:28

2022-08-03 10:45:04

人工智能網(wǎng)絡安全

2021-09-13 09:01:02

Vue 技巧 開發(fā)工具

2022-07-04 06:11:00

預劫持攻擊多因素認證網(wǎng)絡攻擊

2009-11-23 19:51:48

ibmdwWeb

2021-11-18 10:37:28

加密挖礦加密貨幣安全觀察

2011-03-24 17:28:58

網(wǎng)絡數(shù)據(jù)庫
點贊
收藏

51CTO技術棧公眾號