华为云官网性能优化实践

5,944 阅读7分钟

对于web性能的优化分析,我们应该从两个大的方面来着手讨论,即:加载优化和渲染优化,当然我们还有其他更多的优化手段,那么在华为云,我们是怎么做性能优化的呢?

加载优化

image.png image.png

如上图所示是一个完整网络请求的耗时分析过程:

  • Queuing:等待可用连接,优先级、连接数、分配磁盘缓存
  • Stalled/Blocking:请求等待发送所用的时间
  • DNS Lookup:DNS查询所用时间
  • Initial Connection / Connecting:建立连接所用时间,TCP握手/重试和协商SSL的时间
  • Request Sent / Sending:发出网络请求所用时间
  • Waiting (TTFB): 最初的网络请求被发起”到“从服务器接收到第一个字节前”所花费的毫秒数
  • Content Download / Downloading:接收响应数据所用的时间 基于此我们可以针对性的作如下优化:

1. 优化网络连接

网络连接的优化主要有三个规则:使用CDN加速、减少DNS查找、避免重定向。

  • CDN:CDN是地理上分布的web server的集合,用于更高效地发布内容。
  • DNS查找:DNS用于映射主机名和IP地址,一般一次解析需要20~120毫秒。
  • 重定向:将一个URL重新路由到另一个URL。重定向功能是通过301和302这两个HTTP状态码完成的。 image.png

2. 预加载

  • preload: 浏览器会在遇到如下link标签时,立刻开始下载main.js(不阻塞parser),并放在内存中,但不会执行其中的JS语句。preload主要用于预加载当前页面需要的资源。
<link rel="preload" href="/main.js" as="script"> 
  • prefetch:用来初始化对后续导航中资源的获取。prefetch指定的资源获取优先级是最低的。prefetch主要用于加载将来页面可能需要的资源。
<link rel="prefetch" href="/images/big.jpeg"> 
  • dns-prefetch:可以指示浏览器去预先解析DNS域名。这样可以减少将要打开页面的延迟。DNS请求在带宽方面非常小,但延迟非常高,特别是在移动网络上。
<meta http-equiv="x-dns-prefetch-control" content="off">
<link rel="dns-prefetch" href="http://www.spreadfirefox.com/">

3. 多域名加载资源

浏览器在同一个域名之下的并发加载资源数量是有限制的,例如IE6、7是两个,IE8是6个,chrome个版本也不一样,一般是 4-6 个。如果能够将静态资源分布在多个域名下,变相的绕过浏览器的这个限制。 image.png

4. 减少HTTP 请求

  1. 合并js文件
  2. 合并css文件
  3. 雪碧图的使用(css sprite)
  4. 使用base64表示简单的图片 上述四个方法,前面两者我们可以使用webpack之类的打包工具进行打包;雪碧图的话,也有专门的制作工具;图片的编码是使用base64的,所以对于一些简单的图片,例如空白图等,可以使用base64直接写入html中。

5. 减少资源体积

image.png

6. 图像优化

  • 消除多余的图像资源
  • 尽可能利用 CSS3 效果
  • 图片裁剪
  • 网络字体图标库
  • 图像压缩
  • 不要缩放图片 image.png

7. js启动优化

  • 仅下载用户所需的代码
  • 移除未使用的代码。
  • 只加载可视区域需要的资源(图片懒加载的机制)
  • Defer加载JS
  • Webpack动态导入功能(路由配置懒加载)
  • 最小化引入依赖

image.png image.png

8. 延迟加载

延迟加载是一种在加载页面时,延迟加载非关键资源的方法, 而这些非关键资源则在需要时才进行加载。 就图像而言,“非关键”通常是指“屏幕外”。其过程大致如下:(关于图片延迟加载的方案可以看我的文章juejin.cn/post/697794…

  1. 访问一个页面,并开始滚动阅读内容。
  2. 在某个时刻,您将占位符图像滚动到视口中。
  3. 该占位符图像瞬间替换为最终图像。 监听视窗变化,检测图片是否在可视区域 image.png 当目标(target)元素与设备视窗或者其他指定元素发生交集的时候执行 image.png

9. HTTP缓存

image.png

10. 离线缓存

Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。使用Service Workers线程,可以劫持连接、编撰以及过滤响应。 这是一个很强大的工具。 因此为了安全考虑,仅支持在 HTTPS 的页面上注册 Service Worker。 image.png 注册 Service workers 之后,可以用来缓存CSS、图像、字体、JS、模板等静态资源:

self.addEventListener('install', function (event) {
    event.waitUntil(caches.open('mysite-static-v3').then(function (cache) {
        return cache.addAll([
            '/css/whatever-v3.css',
            '/css/imgs/sprites-v6.png', 
            '/css/fonts/whatever-v8.woff', 
            '/js/all-min-v4.js'
        ]);
    }));
});

11. 使用HTTP/2

http2 相对于http1 的改进体现在:

  1. 多路复用
  2. 二进制分帧
  3. 首部压缩
  4. 服务端推送 image.png image.png

加载优化总结

  • 去除不需要的资源:压缩所有的资源,去除未使用的代码,如非必要不引入依赖
  • 根据路由分割代码:只加载当前需要的资源,其它资源采用懒加载方式
  • 缓存代码:按变更频率将代码打包到不同的文件中去,这样代码仅在有变更后才会下载
  • 跟踪包大小:使用工具( webpack-dashboard、webpack-bundle-analyzer)持续关注包的大小变化,及时优化包大小

渲染优化

我们先了解下页面渲染的整个流程:

image.png image.png

1. 优化js执行

  • 对于动画效果的实现,避免使用 setTimeout 或 setInterval,请使用 requestAnimationFrame。
  • 将长时间运行的 JavaScript 从主线程移到 Web Worker。
  • 使用微任务来执行对多个帧的 DOM 更改。
  • 使用 Chrome DevTools 的 Timeline 和 JavaScript 分析器来评估 JavaScript 的影响。

2. 缩小样式计算的范围并降低其复杂性

用于计算某元素计算样式的时间有两方面组成:大约有 50% 用来匹配选择器,而另一半时间用于从匹配的规则中构建 RenderStyle(计算样式的表示),通过添加和删除元素,更改属性、类或通过动画来更改 DOM,全都会导致浏览器重新计算元素样式,在很多情况下还会对页面或页面的一部分进行布局(即自动重排),这就是所谓的计算样式的计算。因此减少css渲染时间的核心在于以下两点:

  • 降低选择器的复杂性;使用以类为中心的方法,例如 BEM。
  • 减少必须计算其样式的元素数量。 image.png

3. 消除阻塞渲染的 JavaScript 和 CSS

  1. CSS 不会阻塞 DOM 的解析,但会阻塞 DOM 渲染。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。
  2. JS 阻塞 DOM 解析,但浏览器会"偷看"DOM,预先下载相关资源。
  3. 浏览器遇到 script 且没有defer或async属性的 标签时,会触发页面渲染,因而如果前面CSS资源尚未加载完毕时,浏览器会等待它加载完毕在执行脚本。 image.png

其他优化

1. API调用的优化

  1. 精简字段,只获取必要的数据:请求时指定返回的字段
  2. 减少请求数:在中台将业务处理完成后返回;中台提供批量处理请求的能力
  3. 缓存数据
  4. API 的查询语言 image.png

2. SSR 服务端渲染 —— 提升首页KPI

image.png

3. CSR 客户端渲染

image.png

4. 避免过早优化和过度优化

  • 不要浪费时间做那些根本不重要的优化
  • 尽量把代码写简单些,提供可读性,增强其可维护性