优化系列之图片处理 - junruchen/junruchen.github.io GitHub Wiki

性能优化中的图片优化。图片优化技巧,推荐阅读

目录

  • 懒加载
  • 缓预加载
  • webP
  • 关于图片优化的其他方案
    • svg与雪碧图
    • 图片压缩与域名处理
  • 关于图片的扩展知识
    • 图片是否需要Gzip压缩
    • 图片在日志上报中的使用

一、懒加载

什么是图片懒加载?

即只有当图片出现在浏览器的可视区域时,才去加载图片,在加载之前使用一张默认图片或者背景色代替。

优点是:减少页面加载时的图片请求,减轻服务器压力,减少页面的加载时间。

实现原理

主要是依据:页面中的img元素只有存在src属性时,浏览器才会发送网络请求 这一特性来实现。

步骤:

  • 为图片设置一个可以记录图片路径的属性,如data-src
  • 监听页面滚动,当图片出现在可视区域时,设置图片的srcdata-src

下面是一个简单的例子:

/* -设置加载时、加载完成的样式- */
.lazy {
  opacity: 0;
  min-height: 200px;
  transition: opacity .5s linear;
}
.lazy.loaded {
  opacity: 1;
}

react中使用的简单写法

import React, { useEffect } from 'react';

// 配置项
const placeHolder = 'placeholder.png' // 默认图片地址,也可直接设置图片背景色
const threshold = 200 // 距离视窗底部多少像素开始加载
const lazyClss = 'loaded' // 加载成功后样式,用来增加过滤动画等效果

function LazyloadImg() {
  // 需要展示的大量图片  
  const imgUrl = [
    'https://cdn.dribbble.com/users/772985/screenshots/7043973/pika_1_1x.jpg',
    ...
  ]

  useEffect(() => {
    const domScroll = () => {
      const clientHeight = document.documentElement.clientHeight || window.innerHeight
      document.querySelectorAll('.lazy').forEach(el => {
        
        // 设置默认图
        if (placeHolder && !el.src) {
          el.src = placeHolder
        }

        // 判断当图片在可视区内时,加载图片,并设置样式
        const imageTop = el.getBoundingClientRect().top
        const dataSrc = el.getAttribute('data-src')
        if (imageTop <= clientHeight + threshold && el.src !== dataSrc) {
          el.src = dataSrc
          if (lazyClss) {
            el.classList.add(lazyClss)
          }
        }
      });
    }

    domScroll()

    window.addEventListener('scroll', domScroll)

    return () => {
      window.removeEventListener('resize', domScroll)
    }
  }, [])

  return (
    <div>
      {imgUrl.map((item, idx) =>
        <img className="lazy" data-src={item} key={idx} alt={'图片' + idx} width="100%" />)
      }
    </div>
  );
}

export default LazyloadImg;

点击查看详细代码 点击查看示例效果

二、预加载

什么是预加载?

即将所需资源提前加载到本地,等需要时直接从缓存中获取资源。

优点是:在页面记载之前对主要资源进行预加载,减少用户等待时间。

实现方式

1、借助img标签

<img src="xxx" style="display:none"/>

2、使用XMLHttpRequest,会存在跨域问题

const xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.onreadystatechange = callback;
xmlhttprequest.open('GET', urls[0], true);
xmlhttprequest.send();
function callback() {
    if (xmlhttprequest.readyState === 4 && xmlhttprequest.status === 200) {
        console.log('success', xmlhttprequest.responseText)
    } else {
        console.log('error');
    }
}

3、使用 Image() 对象,较常用的方式

//预加载
function preloadImg (urls, callback) {
    const images = [];
    const successImgs = [];
    const errorImgs = [];
    const done = () => {
        if (successImgs.length + errorImgs.length === images.length) {
            callback({
                success: successImgs.length,
                error: errorImgs.length,
                successImgs,
                errorImgs
            });
        }
    }

    if (typeof urls === 'string') {
        urls = [urls];
    }

    urls.forEach((url) => {
        const idx = images.length
        images[idx] = new Image();
        images[idx].src = url;
        images[idx].onload = function () {
            successImgs.push(this);
            done();
        };
        images[idx].onerror = function () {
            errorImgs.push(this);
            done();
        }
  })
}

// 使用

preloadImg(images, (res)=> {
    // 其他处理
});

懒加载与预加载的区别

两者均可达到页面性能优化的效果,区别是,懒加载可降低服务器压力,而预加载会增加服务器压力。

三、webP

webp在项目中的实践

四、其他关于图片优化的方案

1、雪碧图与SVG

svg图片的特性:

  • 矢量图形,不论是放大还是缩小,展示效果都是一样的
  • 矢量图是使用相对点保存数据的,与位图的像素点相比,svg格式的图片大小更小,因此响应也更快一些
  • svg图形具有可控性,可自由的更改颜色、增加动画等。

雪碧图的优点:

  • 将多个图片合并为一张图片,减少网络请求,减小图片的总大小
  • 维护更方便,多应用于网页图标等

在传统的项目中,大多是直接将多个小图组合为一张大的图片,然后借助background中的background-position属性进行图标定位。

而随着Iconfont等各类图标库的兴起,svg中的symbol元素可以说是雪碧图的最佳实践了。

下面是一个symbol引用的例子

<!--Icon-->
<svg>
    <symbol id="icon-windows" viewBox="0 0 1024 1024">
        <path d="M491.18331146 178.94070816L907.5078125 116.4921875v370.52902222H491.18331146z"  ></path>
        <path d="M116.4921875 233.06348037l319.1809845-47.18439102v305.30422212H116.4921875z"  ></path>
        <path d="M491.18331146 845.05929184L907.5078125 907.5078125V546.69345093H491.18331146z"  ></path>
        <path d="M116.4921875 790.93651963l319.1809845 47.18439102V546.69345093H116.4921875z"  ></path>
    </symbol>
</svg>

<!--使用-->
<svg class="icon" aria-hidden="true">
    <use :xlink:href="#icon-windows"></use>
</svg>

如果项目中存在大量图标,建议使用iconfont引入的形式。

2、关于图片压缩

对于静态图片,在使用之前可使用类似 TingPNG 的工具进行无损压缩,并引入cdn缓存。

对于用户上传的图片,如果只是上传到个人服务器,可压缩后上传。如上传到图片云存储平台,则可使用平台支持的对象处理策略,对图片进行压缩、裁剪等处理。

如果条件允许,可为图片配置单独的域名,或使用http2.0来避开网络请求的数量限制。

五、关于图片的扩展知识

图片是否需要gzip压缩

不需要!

网站开启gzip压缩,是比较常见的优化方案。浏览器默认只会启动html文件的压缩,css、js文件等需要额外配置,点击查看启动gzip的详细配置

对于图片、flash的swf文件等是不需要做gzip压缩的,主要原因是这类资源本身就压缩,开启Gzip压缩后体积也不会有太大的变化,反而浪费资源

图片在日志上报中的使用

前端监控为什么要用GIF打点?

⚠️ **GitHub.com Fallback** ⚠️