2

11s到⚡1s,性能优化之首屏加载

 2 years ago
source link: https://blog.p2hp.com/archives/8116
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

全文共6511字/词,阅读大概需要13分钟,太长不看党请直接移步「开始优化」部分直接查看优化手段

前段时间公司服务器网络波动,网站访问变慢,一些性能问题也随之暴露了出来。纷纷反馈在这样的弱网条件下,访问新项目时,加载了近1分钟都没加载出来,而访问其他页面顶多也就30-40s。

在网络恢复后,尝试访问了下页面,无缓存首次打开需要等待近11s的时间,最大的资源达到了3.7M...

在对项目做了一些优化处理后,再次无缓存打开可以发现网页几乎是秒开,平均耗时在1s以内

在这里总结记录一下,基本上都是一些常规可复制的优化手段,希望能为同样想优化网页性能的你提供思路~

933ee777419a42039b164bb14484458d~tplv-k3u1fbpfcp-watermark.awebp

Network

Slow3G条件下22-25s加载完成

a58547cd6b0943979ce52a64e7488126~tplv-k3u1fbpfcp-watermark.awebp

lighthouse

2ad48c25223740a997624155b57443c4~tplv-k3u1fbpfcp-watermark.awebp

hiper

关于性能优化

在开始之前,我们需要明白一个原则:性能优化的最终目的是提升用户体验
简而言之就是让用户感觉这个网站很「快」(至少不慢hh),这里的「快」有两种,一种是「真的快」一种是「觉得快」

  • 「真的快」:可以客观衡量的指标,像网页访问时间、交互响应时间、跳转页面时间
  • 「觉得快」:用户主观感知的性能,通过视觉引导等手段转移用户对等待时间的关注

做好这两方面都能提升用户对网站的性能评价。

另外就是软件工程没有银弹,一种优化方案可能适用于大多数项目,但是某些特殊情况下很可能会起反效果。

举个,由于浏览器有单域名下并发请求限制,通常我们会将依赖统一打成一个vendor包(vue-cli默认策略),减少首屏请求数,且依赖不变动的情况下文件指纹不变,可以有效利用304缓存。在依赖不多的情况这么处理确实有助于提升加载速度,但一旦依赖多起来,vendor就会特别的大,在弱网条件下,会严重拖慢页面显示。这显然不是我们想要的,所以我们根据情况会对vendor进行拆分,比如拆分到CDN,或者直接拆分到页面中

因此,我们在做性能优化过程中,必须根据最终能给用户体验带来的提升权衡后做出适合当前项目的选择

指标和目标

目标会影响我们在过程中的决策
指标则用来度量我们的目标

首先我们需要确定目标,根据场景和项目复杂度不同,制定的目标也不同,比如希望比竞品快20%,或者符合标准的"2-5-10"原则等等

这里我定下的目标是

  • 正常网速下,2s内加载完成
  • 弱网下,30s内加载完成

关于指标这块,简单介绍下常见指标

  • FCP(First Contentful Paint):白屏时间(第一个文本绘制时间)
  • Speed Index:首屏时间
  • TTI(Time To Interactive): 第一次可交互的时间
  • lighthouse score(performance):Chrome浏览器审查工具性能评分(也可以npm install -g lighthouse,编程式调用)

通过性能调试工具可以直观便捷地获取这些指标,比如Newwork、k6、hiper、Lighthouse...。具体可以看我关于性能调试工具的另一篇文章

Network分析

7b3ec3cba347427babb4c5a7f928847d~tplv-k3u1fbpfcp-watermark.awebp

优化前Network

从Network上我们发现主要问题在3.2M的chunk-vendor.js上

  • 体积太大,下载慢
  • 阻塞了其他资源下载

Lighthouse分析

e531bfbeb5bf4c3096e2bb14d9b44919~tplv-k3u1fbpfcp-watermark.awebp

优化前Lighthouse

Performance分析

由于本次不涉及到应用内场景性能优化,Performance分析跳过...

dist目录分析

  • 整体体积太大,近5M
  • 出现了若干不应出现的静态资源,比如页面上没引用到SVG图标、应该被内联的小图等
  • 部分图片资源较大,最大的达到仅400KB

Webpack Bundle分析

0fc05bec2982410db86cd0a860ee7d57~tplv-k3u1fbpfcp-watermark.awebp

优化前Bundle

从webpack bundle可以看出,问题着实不少

  • 未剔除项目模板用到的冗余依赖,比如g2、quill、wangEditor、mock等
  • 一些没用到的Ant-design组件由于全局注册也一并打包了进去
  • 项目中只用到几个Ant-Design/icons,但却被全量引入
  • moment和moment-timezone重复,且体积较大
  • core-js体积较大
  • 打包策略不合理,导致chunk-vendor太大

⚡排查并移除冗余依赖、静态资源

内容(点击展开/收起)

⚡构建时压缩图片

内容(点击展开/收起)


npm i image-webpack-loader -D

chainWebpack:  {
     (isProd) {
        
         imgRule = config.module.rule()
        imgRule
            .test()
            .use()
            .loader()
            .options({ :  })
            .end()
    }
}

⚡使用webP图片

内容(点击展开/收起)

./cwebp -q 75 login_plane_2.png -o login_plane_2.webp
 main.js
.addEventListener(,  {
    const isSupportWebP = .createElement()
    .toDataURL()
    .indexOf() === 
    .documentElement.classList.add(isSupportWebP ?  : );
})
 css
.support-webp .bg{
    background-image: url();
}

.-support-webp .bg {
    background-image: url();
}

⚡优化SVG图标

内容(点击展开/收起)

 install
 i svg-sprite-loader -D
 vue.config.js
chainWebpack:  {
     SVG处理
    config.
      .rule()
      .exclude.add(resolve())
      .end()
    config.
      .rule()
      .test()
      .include.add(resolve())
      .end()
      .use()
      .loader()
      .options({
        symbolId: 
      })
      .end()
    
}

 req = .context(, , /\.svg$/)
 requireAll =  requireContext.keys().map(requireContext)
requireAll(req)


 

 Vue  
 CaSVG  
Vue.component(, CaSVG)


<template>
  
...


npm i svgo-loader -D



...
.end()
.()
.loader()
.end()

⚡优化Ant-design-vue体积

内容(点击展开/收起)

⚡优化Ant-design-icon体积

内容(点击展开/收起)


resolve: {
  : {
    : path.resolve(__dirname, )
  }
}

 {   LoadingOutline }  

⚡优化moment、moment-timezone体积

内容(点击展开/收起)


plugins: [
  
   webpack.IgnorePlugin(, /moment$/),
],

moment.tz().format()

moment.utcOffset().format()

 AntdDayjsWebpackPlugin = ()
configureWebpack: {
    ...
    plugins: [
       AntdDayjsWebpackPlugin({ : , :  })
    ],
}

⚡优化core-js体积

内容(点击展开/收起)


. = {
  presets: [
    ,
    [
      ,
      {
        : , 
        : 
      }
    ]
  ],
  plugins
}

⚡优化分包策略

内容(点击展开/收起)

optimization: isProd ? {
  : {
    : ,
    : , 
    minSize: , 
    cacheGroups: {
      : {
        
        
        name() {
          
           packageName = .context.match()[]
          
          
            
        },
        : ,
        : ,
        : 
      }
    }
  },
  : { :   }
} : {}

⚡优化路由懒加载

内容(点击展开/收起)

{
    : ,
    name: ,
    component: () => (/* webpackChunkName:  */ ),
}

⚡开启HTTP2

内容(点击展开/收起)


listen  http2;
 -s stop && nginx

⚡Gzip压缩传输

内容(点击展开/收起)


gzip on;

gzip_min_length 1k;

gzip_comp_level 6;

gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ;

gzip_static on

gzip_vary on;

gzip_http_version 1.1;

 CompressionPlugin = ()

chainWebpack:  {
    (isProd) {
        config.plugin()
            .use( CompressionPlugin({
                : , 
                threshold: , 
                deleteOriginalAssets:  
            }))
    }
}

⚡Prefetch、Preload

内容(点击展开/收起)

⚡托管至OSS + CDN加速

内容(点击展开/收起)

感知性能优化

白屏时的loading动画

内容(点击展开/收起)

首屏骨架加载

内容(点击展开/收起)

感知优化的一些补充

首屏以外的一些场景优化,更多相关内容比如图片懒加载、组件懒加载等 后续文章会做介绍

渐进加载图片

内容(点击展开/收起)

路由跳转Loading动画

内容(点击展开/收起)

本文只介绍了首屏加载场景下的性能优化,实际上性能优化远不止这些内容,SPA的加载性能指标采集光靠Lighthouse、slow 3G模拟真的可信吗?除了加载场景外的其他方面呢?构建速度、操作流畅性...

性能优化影响的,不仅是用户体验,还影响了转化率、搜索引擎排名,这些因素都会对最终的流量、销量等收入造成影响

来自Google的数据表明,一个有10条数据0.4秒能加载完的页面,变成30条数据0.9秒加载完之后,流量和广告收入下降90%。

Google Map 首页文件大小从100KB减小到70-80KB后,流量在第一周涨了10%,接下来的三周涨了25%。

亚马逊的数据表明:加载时间增加100毫秒,销量就下降1%。

立场不同,看问题角度也会变化,比如对老板来说最终目的其实是搞钱hh,用户体验这些花里胡哨的,别人不一定懂。

用户体验 × money √

所以如果必要,请在过程前后做好性能收益的数据监控和分析,在性能优化和产品指标之间建立正向联系,方便自上而下的推动技术方案的执行。这才是你说服上司或领导投入成本到性能优化上的重要依据

性能优化算是老生常谈的话题了,但部分人在面对怎么做性能优化的问题时,仅仅只是罗列出各种常见优化手段,更有深度的答案应该是遇到什么性能问题,针对这个问题围绕某些性能指标采取了什么手段,手段是否带来了其他问题,怎么权衡,最终达到了什么样的效果。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK