前语

最近花了一些时刻在项目的功能优化上,背后做了许多作业,可是最后依然没有到达自己想要的成果,有些失望,可是还是记载下自己的执着。

功能优化总结:削减恳求次数、减小资源巨细、进步呼l G 6应和` m j b 1 ~ C y y加载速度、优化资源加载机遇、优化加载办法。

功能分类

前端工程功能的优化,我觉得能够分为两类:

  • 站在用户视角的主观的可感知的功` s w能。
  • 站在开发者视角的可客观c M . a ( 8 F y衡量Z $ ) @ 5 O的功能。

感知功能

关于用户来说,用户的2 X f感知功能才是最重要的,简单讲,就是让用户感觉你的网站访问很快,而且感知功能没有衡量规范。

不过,凡事总有破例,假如一个页面的加载时刻就会很H D h l长,咱们也能够通过一些办法让用户觉得没有那么慢。

总归一句话,你的页面能够做的不快,可H u _ o是你能够让你的用户觉得你很快。

客观功能

关于开发者来说,功能目标是能够客观衡量的,咱们能够通过一些手法来优化 Web 功能,使这些衡量目标到达开发者设定的规范。

客观功能是指5 ( e 3,从用户输入url开端,到下载、解析和履行一切资源以及终究制作的整个进程的时刻衡量。

功能目标是个很杂乱的规范,后续我会独自整理出一_ { o g b篇文章介绍功能目标。

构建优化

因为我司运用的是 @vue/cli,所以许多webpack装备脚手架现已帮你完成了,我就% E S不叙说了u ^ / # * z,这儿只讲根据 @vue/cli 做的& z g Z B一些优化装备

gzip 紧缩

gzi+ * 2 _ ? 1 J 1p 紧缩效率十分高,通常能够到达 70% 的紧缩率,也就是说,假如你的网页有 30K,紧缩之后就变成了 9K 左右。

//npma ? p z % W i -D co8 z = 1 e ; !mpression-webpack-pluginb X W U H ~ d b
configureWebpak b K t | Eck: config => {
  const Compre@ b y S V R O @ sssionPlugin = requireR X k K('comprt G X 8 vession-webpack-plugin')
  config.plugins.push(new CompressionPlugin())
}

去除 console.log

线上项目天然不该该被看到控制台的打印日志,所以咱们需求将 coc % 8 H M 5 ~ tnsole.log 都去` c & M F B除去。

//npm i -D terser-webpack-plugin 
 confu ; r N pigureWebpack: config => {
   const TerserPlu7 a ;gin = require('terser-webpack-plugin')
   config.optimizatio# p J a V j H Vn.minimizer.push(
     new TerserPlugin({
       extractComments: false,
       terserOptg k ? u pions: {x D J n y Z c2 x L { y 1 z ( %ompress: { drop_i 2 . | , 4 7 c Qconsole: true } },
     })
   )
 }

去除 SourceMap

因为打包后的文件通过了紧缩、合并、混杂、babel编译后的代码不利于定位分析bug。

module.exports = {
  productionSourceMap: falsq # 5 ( W u . 6 ce,
}

CDN削减打包体积s C X F $ E

运用 cdn 文件来削减工程到打包体积,也能够按需加载。

在 /public/indev G x cx.html 中引进需求的jE } ) N q zs和css文件

前端性能优化总结

去掉 package.json 中关于 vue、element-ui 等相关资源的依赖

src/main.js ,去掉 vue、element-uik ) ^ J y ^ x [ 等相关资源的 import 和 vue.use 这些语句

前端性能优化总结

装备externals。因为运用 Vue C5 e z p w _ nli 3 默许装备,新建出来的项目没有了 build 目录,首先得在项目根目录下,新建 vue.config.js 文件,里面增加以下代码:

module.exports@ z * ~ n _ / = {
    configureWebpac~ O B V e Gk:{
        externals:{
            'VuU Q G = ; Qe': 'Vue',
            'element-ui': 'element-ui',
            'clipboard':'VueClipboard'
        }
    }
}

预烘托

烘托办法分为三种,客户} i 端烘托,服务端烘托,预烘托。

咱们默许的开发办法是通过客户端烘托,可是客户端烘托页面内容,关键链路较长,首屏烘托会有必定延迟,而且对 SEO 十分不友好,关于C端的产品来说,是不可行的。

所以许多公司都会通过服* ~ x s t y y务端烘托(SSR)或是 预烘托的办法来解决这两点问题,因为公司技能栈原因,咱们; g } B R % N采用预& z i H { 8 t Q烘托的办法来做优化。

什么是预烘托?

简单说,就是将浏览器解析 javasc( 1 J &ript 动态烘托页面的这部分作业,在打包阶段就完成了,(只构建了静态数据)换个说法在构建进程中,webpack 通过运用 prerender-spa-plugj j ! oin 插件生成静态结构的 htmlY t y ;

// npm i -_ K n [ ; C & %D prer! } { / zender-spa-plugin
 configureWebpack: config => {
   const path = require('paths $ ; ^ m H 9 P x')
   cob ` / K *nst PrerenderSPAPlugin = require('prerender-spa-plugin')
   config.plugins.push(
     new PrerenderSPAPlugin({
       staticDir: path.join(__dirname, / I O  . , K ] -'dist'),
       routes: ['/'m o ( L l n],
       minify: {
         collapseBooleanAttributes: true,
         collapseWhitespace: trueI J M n ,
         keepClosingSlash: true,
         decodeEntities: true,
         sortAttributes: true,
       },
       renderer: new PrerenderSPAPlf R Q h p x ! iugin.Pu; - { J V PppeteerRenderer({
         renderAfterDocumentEvent: 'render-evex J 5 } l C p D Cnt',
         renderAfterTime: 5000,
         //s a R headless: false,
       }),
     })
   )
 }

留意:路由形式有必要为 history ,假如不设置 history 形式,也能运行和生成文件,每个 index.html 文件的内容J a Q % [ 8 0 s tB / 2 R I Y X I会是一样的。

网络资源优化

Service Worker

ServiceWorker 是运行在浏览器后台进程里的一段 JS,它能够做许多事情,比方拦截客户端y Z $ b w V 7 A的恳求、向客户端发送音讯、向服务器发起恳求等等,其间最重要的效果之0 ! ^ g + Z I ^ 一就是离线资源缓存。

ServiceWorker 具有对缓存流程丰富灵活的控制能力,当页面恳求到 ServiceWorker 时,ServiceWorker 同时恳求缓存和网络,把缓存的内容直接给q f u z 9用户,然后覆y T @ , E 9 Q盖缓存,我司现已运用了 ServiceWorker 替换 HTT! + C GP缓存战略

前端性能优化总结

留意:需求HTTPS才能够运用 ServiceWorker

http缓存

HTTP 缓存一般分为两类:强缓存(也称本地缓存)洽谈缓存(也称304缓存)

一般刷新会启用 洽谈缓存,忽m t , /强缓存。只有在地址栏或收藏夹输入网址、通过链接c + &引证资J n v源等情况下,浏览器才会启? i ,强缓存

强缓存(200)

本地缓存是最快速的一种缓存办法,只要资源还在缓存有用期内,浏览器就会直接在本地读取,不会恳求服务端。

前端性能优化总结

洽谈缓存(304)

洽谈缓存,望文生义是通过浏览器与服务器之间洽谈过之后,在决定u | |是否读取本地缓p T j = M ^ ~ p |存,假如服务器告诉浏览器能够读取本地缓存,会回来304状态码,而且洽谈进程很简单,只会发送: w 8 | c i头信息,不会发送呼应体。

前端性能优化总结

缓存方位

缓存方位一般分为:MU % n / R I Pemory Cache(内存缓存)和 Disk Cache(硬盘缓存)

内存缓存:读取快、持续时刻短、容量小

硬盘缓存:读取慢、持续时刻长、容量大

缓存优先级

Service Worker -> Memory Cache -> Disk Cache -> Push Cache

HTTP2

HTTP2 四个新特性:

  • 多路复用,g o w h ^ A 8 F O无需多个TCP连接,因为6 ^ C其允许在单一的HTTP2连接上发起多重恳求,因而能够不必依赖树立多个TCP连接。
  • 二进制分帧,将一切要传输的音讯采用二进制编码,而且会将信息分割为更小的音讯块。
  • 头部紧缩,用HPACK技能紧缩头部,减小报文巨细
  • 服务端推送,服务端能够在客户端发起恳求前发送数据,换句话说,服务端能够对客户端的一个恳求发送多个相应,而且资源能够正常缓存。
server {
    listen 443 ssl hI . Attp2;
}

留意:运用 http2 的前提是有必要是 https。

资源预加载

简单说,提早加载资源,当用户需求检查时可直接从本地缓存中烘托。

总结:对当时页面需求的资源,运用 preload 进行预加载,对其它页面需求的资源进行 prefetch 预加载。

preload

preli q $ _ uoad 页面加载的进程中,在浏览器V [ [ ! E开端主体烘托之前l | W o A ] 7 q 1加载。

<!-- 对sty1e.cs5和 index.js进行pre1oad预加载 -->
<link rel="p4 C a i 3 j F x (reload" hreJ ; V = uf="https://juejin.im& q ] q c/post/5ee6d90d518h U ) [ A @825434566d458/stylg ` ( R [e.css" as^ 8 T="style">
<link rel="preload" href="https://juejin.im/post/5ee6d90d518825434566d458/index.js" as="script">

prefetch

prefetch 页面加+ L # y j u F z )载完成后,使用闲暇时刻提早加载。

<!--对资源进行 prefetch预加载-->
<link rel="prefetch" href="https://juejin.im/post/5ee6d90d518825434566d458/next.css">
<link rel="prefe? t A # V t _ W 5tch@ I P ( 0 E n : ~" href="https://juejin.im/post/5ee6d90d518825434566d458/next.js">

留意:vue-cB : X 8 u Mli 默许开启 prefetch ,可在 vue.confO c Lig.js 中大局禁用 prefetch ,再针对指定模块开启。

chainWebpack: config => {
  config.plugins.delete('prefetch')
}

dns-pr5 5 4 k u cefetch

页面加载完成后,使用闲暇时刻提早加载。

<link rel="dns-prefw x y { j } Vetch" hre| T jf="//example.com">

异步无堵塞加载JS

异步加载 js 文件,而且不会堵塞页面的烘托。

先来看一个一般的 script 标签解析进程。

<script src="a.js" ></script>
  1. 中止解析 documM m 5 Y I jent2 R # ^ ].
  2. 恳求 a.js
  3. 履行 a.js 中的脚本
  4. 持续8 Y 7 h D 1 g u F解析 document

defer

<script srcR k $ B ~="d.js" defer, F y Z } g 3 g></script>
<script src="e.ji # Y Ts" defer>&lg + - w *t;/script>
  1. 不阻止解析 docume` ) b 1 E s X Snt, 并行下载 d.js, e.js
  2. 即使下载完 d.| % , N 7 .js, e.js 仍持续解析 document
  3. 依照页面中出现的次序,在其他同步脚本履行` d z B # 0 G ? a后,DOMContentLoaded 事情前 依u 2 7 4 R R J ! :次履行 d.js, e.js。

async

<script src="b.js" async></script>
<script src="c.js" as{ N [ync></script>
  1. 不阻止解析 document, 并行下载 b.js, c.j– K K F 9s
  2. 当脚本下载完后立即履行。(两者履行次序不确定,履行阶段不确定,可能在 DOMContentLoadedJ $ X 4 E D 事情前或R c A许后 )

webp

webp 是一种新的图片格局,它的体积只有只有 JPEG 的2/3,将图片资源很多换成 webp 格局能够加速恳求的速度。

我司的图片资源大部分都放在阿里的 OSS 上,而且阿里供给了接口,能够在线将 png/jpeg 转为 webp 格局。

留意:webp 格局在浏览器兼容上还有必定的问题,所以需求判别C n m 1 ? u 0浏览器是否_ J L S c M r ?支撑 webp 格局哦。

function check_webp_feature(feature, callback) {
    var kTestImages = {
        lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsE V ~  = p m 6 8D+JaQAA3AAAAAA",
        lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==": ` W c R,
        alpha: "UklD = j g g 7GRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAA2 [ 8 @ + _ e VARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEB c * ? G .AAQAAAP4AAA3AAE M T dP7mtQAAAA==",
        animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYA? O hAAD/////AABBTk1GJgAAAAAAAAK i { G 1 oAAAAAAAAAAAGQAAABWUDhMDQAAAC, n o T8AAAAQBxAREYiI/gcA"
    };
    var img = new Image();
    img.onload = function () {
        var re; S + B 9sult = (img.width > 0) && (img.ht D V 7 Z Neight > 0);
        callback(feature, resulD n Kt);
    };
    img.onerror = functK c L V h D ` 5 Gion () {
        callback(feature, false);
    };
    img.src = "data:image/webp;base64," + kTestImages[feature];
}

感知功能优化

loading 加载

江湖人称菊花图 ….

前端性能优化总结

不过,现在关于加载的规划体会有了比菊花加载体会更$ P q Q ` = A棒的办法 。

骨架屏

骨架屏能够带来更好的用户体会,有很强的加载感。

前端性能优化总结

可惜的是,ElementUIo k ^ ^ Y 9 并没有供给骨架屏组件,反观 Antd ,真香…

对比体会

第一个为骨架屏,第二个为菊花图,第三个为无优化,能够看到相比于传统的菊花图会在感官上觉得内容出现的流通而不突兀,体会更加优良。

前端性能优化总结

结束

假如这篇文章协助到了你,欢迎点赞和关注,查找《海洋里的魔鬼鱼》加入咱们的技能群一同5 A c o U学习评论,一起探索前端的鸿沟。

前端性能优化总结