blog-md icon indicating copy to clipboard operation
blog-md copied to clipboard

无线性能优化--自动化编译响应式图片方案

Open jiangjiu opened this issue 6 years ago • 0 comments

响应式图片方案

现状

对于图片的处理,我们目前一律采用3倍图尺寸的原图格式(.jpg/.png等)

然而,移动端设备千差万别,这样的原图在很大程度上都是一种加载资源的浪费。

从精细化运营出发

从精细化运营的角度思考,我们要关注以下几个问题:

  • devicePixelRatio:

    设备是iphone 8这样的2倍图手机,还是iphone 8 plus等3倍图设备?2倍图手机加载三倍图片,这是一种不必要的流量消耗,同时也降低了性能。

  • 是否支持webp:

安卓机器支持webp图片格式,相比原图,可以降低30-80%左右的图片体积,观感上没有区别,这样的收益是不可忽略的;然而苹果手机完全不支持。

  • 图片资源的hash值:

图片的hash值是根据图片内容尺寸生成的,对于长缓存的资源,这是一种保护,然而也意味着hash值有可能频繁变动,如果需要在运行时做些图片的处理,处理hash值会很头疼。

  • 压缩图片:

    压缩是使用tinypng好,还是其他服务好?免费不?一次上传几张?解压再copy回来?

  • 对首屏图片资源进行预加载:

    现代mvvm框架,只有当生成的DOM元素进入renderTree后,匹配到的css中的图片资源才会开始加载。然而框架下载、初始化、解析模板、生成元素及渲染页面是有时间成本的,这个时间大概在100-1000ms不等。

    -w630

    如上图所示,如果等待页面生成renderTree后才开始下载图片,用户会看到明显的图片加载过程,这也是现代前端框架的弊病浏览器多年以来针对html/css资源做出的优化在使用前端框架后,大部分都失效了。是否可以在框架下载前就开始关键图片的加载呢?

用户体验至上

以上的几点不仅需要在项目开发完进行图片压缩,构建时处理hash值,还要在运行时获取用户设备dpr信息,加载相应的图片资源,考虑是否支持webp等,同时要结合构建时、运行时的信息,将首屏的资源进行预加载。

同时,还有一些webpack编译流程中潜在的问题还未列出。

在频繁迭代的繁重业务中,还需要考虑这些问题,这是一件很不友好的事儿。

但优化图片的需求又是真实存在的,它可以极大的提高用户体验。

FOX中的图片方案

幸运的是,在FOX方案中,上述几点已经得到了解决。

  • 开发者只需正常开发,即可让图片资源根据手机情况自动区分@2x/@3x、webp、progressive、图片压缩。

  • 对于首屏中的关键图片,还可以声明式的预加载。

约定

一. 在stylus/css文件中使用url("")设置jpg/png/jpeg图片

FOX方案内置对css原生的url函数进行了劫持处理,所以确保严格按照以下约定开发:

  • 图片资源切出3倍图,确保在src/assets文件夹下,不要建立子文件夹

  • 无需压缩图片,上线后自动完成图片压缩

  • 设置图片:

    // App.san
    <style lang="stylus">
    
    .test-image
        height rem(1000)
        width rem(1242)
        background-image url("~assets/background.jpg")
    
    
    </style>
    

所有使用url("")声明的jpg/png/jpeg图片都会自动获得优化。

注意:使用background-image属性设置图片。

当使用background时,FOX内部处理属性无法正确判断类名优先级,这种防御式编程可能会带来不想要的结果。

开发体验不打折扣。

接下来,来解决最后一步的首屏资源预加载问题。

2. 在src/config/pagesConfig中声明需要预加载的图片

如果不希望对首屏关键图片做预加载,那么可以忽略这一步。

虽然声明起来也相当简单:

module.exports = {
    // 活动主页
    home: {
        path: '/activity/stargy/home',
        title: '测试主页',
        pageDataApiPath: '/api/index',
        template: 'base.ejs',
        preloadImages: [
            'background.jpg'  // 关键图片声明
        ]
    },
    // 分享页
    share: {
        path: '/activity/stargy/share',
        title: '测试分享页',
        pageDataApiPath: '/api/index',
        template: 'base.ejs'
    }
};

src/config/pagesConfig配置文件中的preloadImages属性,声明需要预加载的图片即可。

此文件详细配置信息可以在src/config/pagesConfig.js 开发的pages配置找到。

深入

progressive排版

FOX响应式图片方案不但会智能区分webp,还默认使用了progressive图片排版

对比baseline图片

体验对比

它和普通的baseline自上而下逐帧加载的排版方式有什么区别呢?来看下面的对比:

当图片需要一定的加载时间时,baseline图片很明显的有加载过程,而且这种体验是突兀的;progressive图片则是一种渐进式的转换,更符合人的感官体验

性能对比

progressive图片比baseline图片加载要快。

通常,当baseline图片加载第一帧时,progressive图片已经将轮廓渲染好,而且浏览器也可以针对这种图片做渲染优化。

唯一的缺点就是几年前图片解码比较消耗cpu和内存,不过在现代移动端机器上已经不是问题了。

实际测试

我们使用chrome自带的lighthouse工具来进行测试,这两个页面都会加载一个140kb的背景图,只是图片排版方式不同

来看页面加载过程及实际性能指标的对比:

很明显,使用progressive图片的页面,页面全白等待加载的时间更短,这体现在Speed Index指标上: 2840ms => 1710ms,这说明页面填充的速度提高了1秒左右。

百度云BOS图片服务

stylus/css编译流程

模块resolve问题

运行时动态添加preload预加载

总结

这就是兼顾了性能及开发体验的FOX响应式图片方案。

jiangjiu avatar Oct 26 '18 06:10 jiangjiu