nicenote/source/_posts/webPerformanceOptimization-2.md
2018-07-13 16:54:43 +08:00

8.4 KiB
Raw Blame History

title date tags categories
nodeJS性能处理 2018-05-30 10:53:33
性能优化
nodeJS

nodeJs 性能处理

引言

一个网站的体验,决定了用户是否愿意去了解网站的功能,而网站的功能,决定了用户是去还是留。特别是网站的性能,如果一个网页的时间打开超过 5s ,绝大部分用户会选择关闭它。

性能极致一直是作为 fea 的最高追求,所以在性能上我们更应关注以下指标:

  • 白屏时间
  • 首屏时间
  • 整页时间
  • DNS 时间
  • CPU 占用率

本文将从以下三大模块展开介绍如何优化网站性能:

  1. 网络传输性能优化
  2. 页面渲染性能
  3. JS阻塞性能

1. 网络传输性能优化

首先我们需要了解页面输入 url 后,经历了哪几个阶段,如下:重定向 → 拉取缓存 → DNS 查询 → 建立TCP链接 → 发起请求 → 接收响应 → 处理html元素 → 元素加载完成。

1.1 浏览器缓存

浏览器向服务器请求时,首先会查询本地是否有缓存文件。我们可以在服务器上设置 Etag 字段来控制缓存存放的位置,存在时便将数据存入硬盘。

缓存有两种情况,分别为: from memory cache 和 from disk cache.

以 nginx 为例来配置nginx

//首先我们先进入nginx的配置文档
$ vim nginxPath/conf/nginx.conf

//在配置文档内插入如下两项:
etag on;   //开启etag验证
expires 7d;    //设置缓存过期时间为7天

然后打开我们的网站,如果响应头部看见该字段则配置成功。

注意是否为强缓存(本地缓存),该操作不会和服务端产生联系,所以需要给文件添加 hash 值。

1.2 资源打包压缩

缓存只是针对第二次访问页面,而首次打开页面的体验优化则需要对资源进行处理,可以分为以下几个方面:

  • 减少请求数
  • 减少请求资源体积
  • 提示网络传输速率

在 webpack 配置时,注意以下几点:

① JS 压缩

new webpack.optimize.UglifyJsPlugin()

② HTML 压缩

new HtmlWebpackPlugin({
  template: __dirname + '/views/index.html', // new 一个这个插件的实例,并传入相关的参数
  filename: '../index.html',
  minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeRedundantAttributes: true,
    useShortDoctype: true,
    removeEmptyAttributes: true,
    removeStyleLinkTypeAttributes: true,
    keepClosingSlash: true,
    minifyJS: true,
    minifyCSS: true,
    minifyURLs: true,
  },
  chunksSortMode: 'dependency'
})

③ 提取公共资源

new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: 'scripts/common/vendor-[hash:5].js'
        })

webpack3, 可能不适用 webpack4

④ 提取 CSS 并压缩

这里我只截取部分片段

rules: [
  {
    test: /\.css$/,
    use: ExtractTextPlugin.extract({
      fallback: 'style-loader',
      use: {
        loader: 'css-loader',
        options: {
          minimize: true
        }
      }
    })
  }
]

⑤ 服务器端开启 GZIP 压缩

gzip on;
gzip_types text/plain application/javascript application/x-javascripttext/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;

不要对图片进行压缩,个人理解为图片内存一般都比较大,服务器处理起来需要消耗 CPU 占内存,压缩后的图片还有可能失真,这样只会适得其反。

1.3 图片资源优化

图片是真正占了传输资源的东西,如果能对这类资源处理极致,效果是显著的。

① 不要在 html 里面缩放图像

比如在一个 200 * 200 的容器里面放入一个 400 * 400 的图片,事实上并不会增加它的清晰度,相反它会让网页加载的速度下降,造成带宽的浪费,所以按照自己的需求选择图片,然后放在服务器最佳。

2M 和 200k 的图片传输是 12s 和 200ms 的差距。

② 使用雪碧图

就是将许多小的图片放在一张图里,从而来减少请求数。

③ 使用字体图标

不管是压缩的图片,还是雪碧图,终归还是图片,都会占用比较大的资源,使用字体图标,可以更进一步优化这个局面。如果项目中有很多小图标,可以考虑使用字体图标。

④ WebP 格式

谷歌开发的一种加快图片加载的格式,压缩体积大约只有 JPEG的 2/3。

1.4 网络传输性能检测工具--Page Speed

谷歌网页测速工具

1.5 使用 CDN

一个项目从服务器到客户端中间可能经过一大堆路由来转发这就相当于直线能到家的路程然而走了很多弯路到达目的地的时间肯定是不一样的。CDN 就是用来处理这个问题。

cdn 一般不和网站主域名相同,为什么?往下看。

① 便于CDN 业务独立,能够独立配置缓存。

为了减低 web 的压力cnd 会遵循前面的 cache 和 expires 头标准来对返回的内容进行缓存,起到加速的功能。一般大型网站都会设置 expires 比较大,这样可以减少请求回源。

② 抛开无用的 cookie减少带宽占用。

cookie 可以通过服务器设置,如果资源同源的情况下,主域名的资源都是带 cookie 的,相对的子域名也会带 cookie。然而一般图片cssjs这一类资源请求是不需要带 cookie 的,带了也没卵用,这时候就是在浪费带宽。

处理了 CND 的问题,随之而来的是 DNS 对域名的解析产生的问题,这会花费额外的时间,增加网络延迟。这个时候 DNS Prefetch 闪亮登场。使用方法如下:

/* 放在 html 头部即可预解析 */
<link ref="dns-prefetch" href="//blog.jzxer.cn">

2. 页面渲染性能优化

2.1 浏览器渲染过程

渲染方面尽量减少重排和重绘,因为它们会影响浏览器的性能。

浏览器的渲染过程User → 浏览器引擎 → 渲染引擎

渲染引擎再ajax、js、css 进行解析。其中 js 解释器独立出来变成了 V8.

2.2 DOM 渲染层与 GPU 硬件加速

页面是由许多层级构建而成3D 图就像一本书一样。它经历了以下的流程:

  1. 浏览器获取 DOM 将其分割为多个独立渲染层。
  2. CPU 将每个层绘制进绘图中。
  3. 将位图作为纹理上传至 GPU显卡绘制。
  4. GPU 将所有渲染层缓存如果下次上传的渲染层没有变化GPU就不用重绘制并复合成最终形成的我们的图像。

布局由 CPU 处理,绘制由 GPU 处理。

此处用到 chorme tools 两个工具Layers 和 Rendering。

Layers

列出页面存在的所有渲染层。

Rendering

  1. paint flashing对页面发生重绘的元素高亮。
  2. Layer Borders高亮边界突出页面中的各个渲染层。
  3. FPS Meter开启小黑窗观察 GPU 占用率。
/* 触发渲染层 */
transform: translateZ(0);
backface-visibility: hidden;

把容易触发排版重绘的元素单独触发渲染层,让他与“静态”元素隔离,让 GPU 分担更多,就是所谓的硬件加速。

2.3 重排和重绘

① 重排

渲染层内部元素布局发生修改,都会导致重新排列,窗口的尺寸发生变化,删除或添加 DOM影响了盒子大小的 css 属性。

② 重绘

既渲染上色,对元素的视觉表现属性,就会引发重绘。

2.4 优化策略

  1. css 属性读写分离:浏览器每次对样式进行操作时,都要进行一次重新渲染(重排 + 重绘),所以我们用 js 对样式进行读写操作时,最好将两者分开,先读后写。

  2. 通过切换 class 或者用元素的 style.css(text) 属性去批量操作元素样式。

  3. DOM 元素离线更新:

  4. 将没用的元素设置为 visibility: hidden可以减小重绘压力。

  5. 压缩 DOM 深度,一个渲染层不要有过深的子元素,少用 DOM 完成页面样式,多使用伪元素或者 box-shadow。

  6. 图片在渲染前指定大小:因为 img 是内联元素,加载后会改变宽高,最好在渲染前就指定大小,或者让它脱离文档流。

3. JS阻塞性能

如果使用了闭包而未将相关资源释放,或者引用了外部链接而将其制空,都会造成内存泄漏,进而大量占用 GPU造成卡顿和死机。可以使用 chrome 的 JavaScript Profile 版块。

服务端使用闭包需谨慎。