前端性能优化

一、简介

web 性能优化包括:无用代码移除 (Tree-shaking)、作用域提升(Scope hoisting)、代码分割(Code-spliting),交叉观察器(Intersection observer)、服务器推送(server push)、客户端提示(clients hints)、HTTP/2、service workers 等等这些手段。

性能优化不是在开发之后!根据性能的影响来做设计决策,性能必须被测量、监测和不断的完善。

以用户为中心的性能指标可以更好地洞察实际的用户体验。

1 古老的雅虎军规

尽量减少 HTTP 请求个数——须权衡
使用 CDN(内容分发网络)
为文件头指定 Expires 或 Cache-Control ,使内容具有缓存性。
~ 避免空的 src 和 href
使用 gzip 压缩内容
把 CSS 放到顶部
把 JS 放到底部
避免使用 CSS 表达式
将 CSS 和 JS 放到外部文件中
减少 DNS 查找次数
精简 CSS 和 JS
避免跳转
剔除重复的 JS 和 CSS
配置 ETags
使 AJAX 可缓存
尽早刷新输出缓冲
使用 GET 来完成 AJAX 请求
延迟加载
预加载
减少 DOM 元素个数
根据域名划分页面内容
尽量减少 iframe 的个数
避免 404
减少 Cookie 的大小
使用无 cookie 的域
减少 DOM 访问
开发智能事件处理程序
用 代替 @import
避免使用滤镜
优化图像
优化 CSS Spirite
不要在 HTML 中缩放图像——须权衡
favicon.ico要小而且可缓存
保持单个内容小于25K
打包组件成复合文本

2 Chrome DevTools的Network面板

传送门

google

2.1 查看 DOMContentLoaded 和 load 事件信息

我们要明白这两个时期先要了解DOM文档加载流程:

  1. 解析HTML结构。
  2. 加载外部脚本和样式表文件。
  3. 解析并执行脚本代码。
  4. 构造HTML DOM模型。// DOMContentLoaded 相当于jQuery中的ready
  5. 加载图片等外部文件。
  6. 页面加载完毕。// load
2.2 查看网络耗时

重定向→拉取缓存→DNS 查询→建立 TCP 链接→发起请求→接收响应→处理 HTML 元素→元素加载完成
网络

2.3 查看资源发起者和依赖项

按住 Shift 并将鼠标悬停在资源上,可以查看其发起者和依赖项。 本部分将您悬停的资源称为目标。
img

二、网络传输性能优化

1. 浏览器缓存

在这里插入图片描述

链接

img

2. 资源打包压缩

  • 减少请求数
  • 减小请求资源体积
  • 提升网络传输速率
  1. JS 压缩 uglifyjs-webpack-plugin
  2. HTML 压缩 html-webpack-plugin
  3. 提取公共资源
  entry: {
    vendor: [
      'react',
      'react-dom',
      'react-native-web',
      'react-router',
      'react-router-dom',
      'mobx',
      'mobx-react',
      'axios',
      'sa-sdk-javascript'
    ],
  },
new webpack.optimize.CommonsChunkPlugin({
  name: ['vendor', 'runtime'],
  // filename: 'static/js/[name].js',
  minChunks: Infinity
}),
  1. 提取 CSS 并压缩 mini-css-extract-plugin
const loaders = [
      isEnvDevelopment && require.resolve('style-loader'),
      isEnvProduction && {
        loader: MiniCssExtractPlugin.loader,
        options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
      },
      {
        loader: require.resolve('css-loader'),
        options: cssOptions,
      },
      {
        // Options for PostCSS as we reference these options twice
        // Adds vendor prefixing based on your specified browser support in
        // package.json
        loader: require.resolve('postcss-loader'),
        options: {
          // Necessary for external CSS imports to work
          // https://github.com/facebook/create-react-app/issues/2677
          ident: 'postcss',
          plugins: () => [
            require('postcss-flexbugs-fixes'),
            require('postcss-preset-env')({
              autoprefixer: {
                flexbox: 'no-2009',
              },
              stage: 3,
            }),
            // Adds PostCSS Normalize as the reset css with default options,
            // so that it honors browserslist config in package.json
            // which in turn let's users customize the target behavior as per their needs.
            postcssNormalize(),
          ],
          sourceMap: isEnvProduction && shouldUseSourceMap,
        },
      },
    ]
  1. webpack 开发环境修改为生产环境
  2. 服务器上开启 Gzip 传输压缩(不要对图片文件进行 Gzip 压缩)

3. 这个就高级了

  1. 识别并删除未使用的 CSS / JavaScript
  2. 修剪 JavaScript 依赖项的大小

举个例子

  1. 异步加载 JavaScript

在这里插入图片描述

没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行

有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)

有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成

  1. 分包 优化首屏

webpack 配置

new webpack.optimize.CommonsChunkPlugin({
      name: ['vendor', 'runtime'],
      // filename: 'static/js/[name].js',
      minChunks: Infinity
    }),
    new webpack.optimize.CommonsChunkPlugin({
      children: true,
      async: 'children-async'
    }),
    new ExtractTextPlugin({filename: 'static/css/[name].[chunkhash:5].css', allChunks: true}),

4. 图片资源优化

  1. 使用大小合适的图片
  2. 使用雪碧图
  3. 【强烈推荐】使用字体图标
  4. 逐步加载图像

阿里矢量图标库
symbol引用

  1. 使用webP (单独讲述)

5. 网络传输性能检测工具——Page Speed

在这里插入图片描述

6. 使用 CDN

7. HTTP / 2

  1. 迁移到HTTPS,然后打开HTTP / 2
  2. 是否采用 IPv6

三、页面渲染性能优化

1. 浏览器渲染过程(Webkit)

在这里插入图片描述

2. DOM 渲染层与 GPU 硬件加速

页面的真实样子就是这样,是由多个 DOM 元素渲染层(Layers)组成的,实际上一个页面在构建完 render tree 之后,是经历了这样的流程才最终呈现在我们面前的:

  • 浏览器会先获取 DOM 树并依据样式将其分割成多个独立的渲染层
  • CPU 将每个层绘制进绘图中
  • 将位图作为纹理上传至 GPU(显卡)绘制
  • GPU 将所有的渲染层缓存(如果下次上传的渲染层没有发生变化,GPU 就不需要对其进行重绘)并复合多个渲染层最终形成我们的图像

从上面的步骤我们可以知道,布局是由 CPU 处理的,而绘制则是由 GPU 完成的。

3. 重排与重绘

  • 重排(reflow):渲染层内的元素布局发生修改,都会导致页面重新排列,比如窗口的尺寸发生变化、删除或添加 DOM 元素,修改了影响元素盒子大小的 CSS 属性(诸如:width、height、padding)

  • 重绘(repaint):绘制,即渲染上色,所有对元素的视觉表现属性的修改,都会引发重绘

4. 优化策略

  1. CSS 属性读写分离:浏览器每次对元素样式进行读操作时,都必须进行一次重新渲染(重排 + 重绘),所以我们在使用 JS 对元素样式进行读写操作时,最好将两者分离开,先读后写,避免出现两者交叉使用的情况。最最最客观的解决方案,就是不用 JS 去操作元素样式,这也是我最推荐的
  2. 通过切换 class 或者 style.csstext 属性去批量操作元素样式
  3. DOM 元素离线更新:当对 DOM 进行相关操作时,例、appendChild 等都可以使用 Document Fragment 对象进行离线操作,带元素“组装”完成后再一次插入页面,或者使用 display:none 对元素隐藏,在元素“消失”后进行相关操作
  4. 将没用的元素设为不可见:visibility: hidden,这样可以减小重绘的压力,必要的时候再将元素显示
  5. 压缩 DOM 的深度,一个渲染层内不要有过深的子元素,少用 DOM 完成页面样式,多使用伪元素或者 box-shadow 取代
  6. 图片在渲染前指定大小:因为 img 元素是内联元素,所以在加载图片后会改变宽高,严重的情况会导致整个页面重排,所以最好在渲染前就指定其大小,或者让其脱离文档流
  7. 对页面中可能发生大量重排重绘的元素单独触发渲染层,使用 GPU 分担 CPU 压力。(这项策略需要慎用,得着重考量以牺牲 GPU 占用率能否换来可期的性能优化,毕竟页面中存在太多的渲染层对与 GPU 而言也是一种不必要的压力,通常情况下,我们会对动画元素采取硬件加速。)

四、JS 阻塞性能

参考资料

(译)2019年前端性能优化清单

goole - chrome devtools

网站性能优化实战——从12.67s到1.06s的故事

  1. ng 设置etag
  2. ng 图片 gzip
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值