Web图片加载

Web端的性能优化很多都集中在对JavaScript和CSS上面,比如"Move Scripts to the Bottom","Put Stylesheets at the Top"等等,很多时候,我们的开发中会忽略掉,图片的优化其实也是非常重要的一部分。

我们关注JS和CSS的重点也是如何能够更快地下载图片。图片是用户可以直观看到的,他们并不会关注JS和CSS。

以最近做的一个页面同花顺理财周为例:

xhr img css/js doc 其他
Size(kb) 1.216 52.331 22 4.8 0
Time(ms) 453 1628 822 164 0

web端的图片加载

在开始本文的介绍之前,先了解一些基础的知识:
在网页中插入一张图片可以使用html的<img>标签[站外图片上传中……(2)],每插入新建一个<img>标签就会新建一个Image 对象。
Image 对象的属性 onload 声明了一个事件句柄函数,当图像装载完毕的时候就会调用这个句柄。
Image 对象的属性 onerror 声明了一个事件句柄函数,当装载图像的过程中发生了错误时就会调用这个句柄。

我们目前在页面中采取的两种加载方式

针对首屏的banner图

<!-- html -->
[站外图片上传中……(2)]

<!-- js -->
function load_img(url, url_s, o) {
    var img = new Image(); //创建一个Image对象,实现图片的预下载
    img.src = url;
    o.src = url_s;

    if (img.complete) { //图片已经被缓存,直接替换
        o.src = img.src;
        return;
    };

    img.onload = function() { //图片下载完毕时替换
        o.src = img.src;
    };
};

load_img(("images/header.png"), ("images/header.jpg"), document.getElementById("img_init"));

原理:用一张很小的图片A替换清晰banner图B优先加载,然后js新建源为图B的Image对象并监控其加载进度,当图B加载完成之后,再替换掉图A。
不足:

  • 功能单一,只能实现单张图片的预加载
  • 只考虑了静态图片的加载,忽略了gif等动态图片,这些动态图片可能会多次触发onload
  • 必须等待图片加载完毕, 仍然有优化空间

滚屏加载(图片的异步加载)

<!-- html -->
[站外图片上传中……(3)]

<!-- js -->
function timeOutLoad(container) {
    this.container = container || document;
    var imgs = [],_num = [];
    var oriImgs = this.container.getElementsByClassName('timeOutLoad');
    for (var i = 0; i < oriImgs.length; i++) {
        var _data = oriImgs[i].getAttribute("data-original");
        if (_data) {
            _num.push(i);
            imgs.push(_data);
        }
    }
    function loadByOne(i) {
        if (imgs.length > 0) {
            _img = new Image();
            _img.onload = function () {
                oriImgs[_num[i]].setAttribute('src', _img.src);
                oriImgs[_num[i]].removeAttribute('data-original');
                loadByOne(i + 1);
            };
            _img.src = imgs.shift();
        }
    }
    loadByOne(0);
}
timeOutLoad(document.getElementById("container"));

原理:

通过判断当图片元素是否出现在视窗范围内后,则去加载图片资源,否则不加载。

延伸

Litten说到加载图片,我们可以谈些什么

特殊状态处理

  • 加载中:在图片开始加载到触发onliad事件之前,展示加载的loading图
  • 加载失败:文字提示,或错误提示图片替代

上报监控

  • 加载失败触发onerror时,上报统计每天图片拉取失败的量
  • 图片加载事件过长,上报分析cdn服务是否异常,或者是网速较慢的用户比例

webp

smaller、*richer *

一个较完善的可行方案

花落红尘 诺诶网络

// 更新:
// 05.27: 1、保证回调执行顺序:error > ready > load;2、回调函数this指向img本身
// 04-02: 1、增加图片完全加载后的回调 2、提高性能

/**
 * 图片头数据加载就绪事件 - 更快获取图片尺寸
 * @version    2011.05.27
 * @author    TangBin
 * @see        http://www.planeart.cn/?p=1121
 * @param    {String}    图片路径
 * @param    {Function}    尺寸就绪
 * @param    {Function}    加载完毕 (可选)
 * @param    {Function}    加载错误 (可选)
 * @example imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function () {
        alert('size ready: width=' + this.width + '; height=' + this.height);
    });
 */
var imgReady = (function () {
    var list = [], intervalId = null,

    // 用来执行队列
    tick = function () {
        var i = 0;
        for (; i < list.length; i++) {
            list[i].end ? list.splice(i--, 1) : list[i]();
        };
        !list.length && stop();
    },

    // 停止所有定时器队列
    stop = function () {
        clearInterval(intervalId);
        intervalId = null;
    };

    return function (url, ready, ,load error) {
        var onready, width, height, newWidth, newHeight,
            img = new Image();
        
        img.src = url;

        // 如果图片被缓存,则直接返回缓存数据
        if (img.complete) {
            ready.call(img);
            load && load.call(img);
            return;
        };
        
        width = img.width;
        height = img.height;
        
        // 加载错误后的事件
        img.onerror = function () {
            error && error.call(img);
            onready.end = true;
            img = img.onload = img.onerror = null;
        };
        
        // 图片尺寸就绪
        onready = function () {
            newWidth = img.width;
            newHeight = img.height;
            if (newWidth !== width || newHeight !== height ||
                // 如果图片已经在其他地方加载可使用面积检测
                newWidth * newHeight > 1024
            ) {
                ready.call(img);
                onready.end = true;
            };
        };
        onready();
        
        // 完全加载完毕的事件
        img.onload = function () {
            // onload在定时器时间差范围内可能比onready快
            // 这里进行检查并保证onready优先执行
            !onready.end && onready();
        
            load && load.call(img);
            
            // IE gif动画会循环执行onload,置空onload即可
            img = img.onload = img.onerror = null;
        };

        // 加入队列中定期执行
        if (!onready.end) {
            list.push(onready);
            // 无论何时只允许出现一个定时器,减少浏览器性能损耗
            if (intervalId === null) intervalId = setInterval(tick, 40);
        };
    };
})();

调用案例:

imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function (){
    alert('size ready: width=' + this.width + '; height=' + this.height);
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,926评论 25 707
  • Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践。他们为此进行了一系列...
    拉风的老衲阅读 1,837评论 0 1
  • 原创文章,未经允许,严禁转载 还记得 图片延迟加载方案 那篇博文吗?当初分析了定宽高值和定宽高比这两种常见的图片延...
    齐修_qixiuss阅读 46,860评论 36 376
  • 第一章 在库茹之野视察两方的军队 1.兑塔茹阿施陀王说:桑佳亚呀!我众儿及潘度诸子两方陈兵圣地库茹之野,跃跃欲战,...
    愛恩阅读 1,246评论 0 1
  • 年龄越大,越觉得生活无时无刻都存在一个永恒的选择题:该不该较真儿。 早上天还没亮,你就被邻居家装修的声音吵醒,该不...
    小迷阅读 558评论 0 1