美文网首页
Web图片加载

Web图片加载

作者: YangEric | 来源:发表于2016-11-11 16:30 被阅读0次

    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);
    });
    

    相关文章

      网友评论

          本文标题:Web图片加载

          本文链接:https://www.haomeiwen.com/subject/xvyfpttx.html