容器启动优化
客户端资源预构建
客户端 Native 对 h5 资源预获取,对 webview 进行预构建。
页面状态保活
页面保活
是指在用户离开当前页面后,可以在返回时恢复上一次浏览页面的状态,而不需要重新加载。
如何实现页面保活?
- Vue 中可以使用内置的
<KeepAlive>
组件(该标签会缓存不活动的组件实例,而不是销毁它们) - React 中没有实现
<keep-alive>
类似的功能,官方推荐以下两种手动保存状态的做法:- 将需要保存状态组件的 state 提升至父组件中保存。
- 使用 css 来控制页面的显示隐藏
网络优化
预解析 DNS
首先前端需要控制域名个数,减少 DNS 解析。
DNS 预解析就是让浏览器在用户访问链接之前解析域名。包括文档所有链接,如图片,CSS,JavaScript 等用户能够点击的 URL。原理:提前解析域名,将解析结果进行缓存,提高网站的访问速度。
为什么需要?
DNS 请求需要的带宽非常小,但是延迟却有点高。
如何开启?
你可以通过在服务器端发送 X-DNS-Prefetch-Control 报头,或是在文档中使用值为 http-equiv
的 <meta>
标签:
html
<meta http-equiv="x-dns-prefetch-control" content="off" />
on:启用 DNS 预解析。在浏览器支持 DNS 预解析的特性时即使不使用该标签浏览器依然会进行预解析。 off:关闭 DNS 预解析。这个属性在页面上的链接并不是由你控制的或是你根本不想向这些域名引导数据时是非常有用的。
X-DNS-Prefetch-Control (非标准)
自动解析:Chromium 会自动解析 href 属性(a 标签),该行为与用户浏览网页是并行的。但为了确保安全,HTTPS 页面不会自动解析。DNS Prefetching - Chromium 官方文档
Chromium 不使用浏览器的网络堆栈,直接使用操作系统的缓存。通过 8 个异步线程执行预解析,每个线程处理一个队列,来等待域名的响应,最终操作系统会响应一个 DNS 结果给线程,然后线程丢弃它,等待下一个预解析请求。
手动强制解析:可以通过使用 rel 属性值为 link type 中的 dns-prefetch 的 标签来对特定域名进行预读取:
html
<link rel="dns-prefetch" href="http://www.spreadfirefox.com/" />
减少 HTTP 请求个数
对请求进行合并。
开启 HTTP/2
HTTP/2 的优势?
二进制分帧(基石)
:新增二进制分帧层,将请求和响应拆分为多个帧,并通过流(Stream)的方式进行传输。每个流都有一个唯一的标识符,可以用来区分不同的请求和响应。这样,多个流可以同时在一个 TCP 连接上进行传输,而不会相互干扰。多路复用/连接共享
:所有相同域名的请求通过同一个 TCP 连接并发完成。在 HTTP1.x 中,并发多个请求需要多个 TCP 连接,浏览器为了控制资源会有 6-8 个 TCP 连接的限制,如果开启了 keep-alive,虽然可以用多次,但是同一时刻只能有一个 HTTP 请求。- keep-alive 是客户端和服务端的一个约定,如果开启 keep-alive,则服务端和客户端在返回和接收 response 后不关闭 TCP 连接。
- 虽然 HTTP/2 支持多路复用,但是在实际应用中,服务器和客户端都可以限制并发请求数量,以控制资源的使用和保证服务质量。因此,并不是所有的请求都会同时在一个 TCP 连接上进行传输,具体的并发请求数量会受到服务器和客户端的配置和限制。
header 头部压缩
服务器端推动(Sever Push)
:主要思想是:当客户端请求资源 A,而服务器知道它很可能也需要资源 B 的情况下,服务器可以在客户端发送请求前,主动将资源 B 推送给客户端。客户端将 B 放进缓存以备将来之需。
HTTP/2 的存在的问题?
- 如果有丢包请求会等待重传,阻塞后面的数据,有可能还不如 HTTP1.1 的多个 TCP 连接以及 TCP+TLS 建立连接的延时。
- TCP 的队头阻塞并没有彻底解决,TCP 为了保证可靠传输,有一个"超时重传"机制,丢失的包必须等待重传确认。
- 多路复用会导致服务器压力上升,多路复用没有自动限制同时请求数。请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 暴增。
- 多路复用容易 Timeout 大批量的请求同时发送,由于 HTTP2 连接内存在多个并行的流,而网络带宽和服务器资源有限,每个流的资源会被稀释,虽然它们开始时间相差更短,但却都可能超时。
如何开启 HTTP/2?
Nginx 上配置。 zhuanlan.zhihu.com/p/29609078
使用 CDN
什么是 CDN ?
全称 Content Delivery Network 即内容分发网络。
用户在浏览网站的时候,CDN 会选择一个离用户最近的 CDN 边缘节点来响应用户的请求。
CDN 的优势?
- CDN 节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。
- 大部分请求在 CDN 边 缘节点完成,CDN 起到了分流作用,减轻了源服务器的负载。
CDN 缓存?
当浏览器向 CDN 节点请求数据时,CDN 节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN 节点就会向服务器发出回源请求,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端。
资源加载
预获取与预加载
prefetch(预获取)
:关键字 prefetch 作为元素 <link>
的属性 rel 的值,是为了提示浏览器,用户未来的浏览有可能需要加载目标资源,所以浏览器有可能通过事先获取和缓存对应资源,优化用户体验。
html
<link rel="prefetch" href="style.css" as="style" />
preload(预加载)
:关键字 preload 作为元素 <link>
的属性 rel 的值,表示用户十分有可能需要在当前浏览中加载目标资源,所以浏览器必须预先获取和缓存对应资源。
html
<link rel="preload" href="style.css" as="style" />
静态资源压缩
webpack 等构建工具 对代码进行 Tree Shaking 和 压缩;
gzip 压缩
HTTP 可以对传输的内容进行压缩,减少网络实际传输数据的大小。原理就是服务器对文件进行 gzip 压缩后,再进行传输,浏览器收到资源后再解压的过程。
- 对于 js、text、json、css 这种纯文本进行压缩,效果特别好,不用改变代码即可提升网站响应速度;
- 压缩过程是需要花费 CPU 资源的,对大文件(图片、音乐等)进行压缩,不仅不能提升网站响应速度,还会增加服务器压力,让网站有明显的卡顿感。
如何开启 gzip 压缩?
需要再 nginx 上进行配置(www.jianshu.com/p/8ab94952d...
浏览器缓存
强制缓存
主要使用 Expires、Cache-Control 两个头字段。两者同时存在 Cache-Control 的优先级更高。当命中强缓存,客户端不再向服务器发送请求,直接从缓存中获取内容,状态码返回 200
-
Expires
:响应头,代表该资源的具体过期时间。是一个 GMT 格式的标准时间。 -
Cache-Control
:请求/响应头,缓存控制字段,精确控制缓存策略。为了让强缓存更精确,HTTP1.1 增加了Cache-Control
字段。Cache-Control
既能出现在请求头又能出现在响应头。
协商缓存
主要有四个头字段。两两配合使用,If-Modified-Since 和 Last-Modified、Etag 和 If-None-Match。当同时存在的时以 Etag 和 If-None-Match 为主。当命中协商缓存,服务器返回状态码 304,客户端直接从本地缓存里面读取文件。
If-Modified-Since
: 请求头,资源最近修改时间,由浏览器告诉服务器。其实就是第一次访问服务端返回的 Last-Modified 的值。Last-Modified
:响应头,资源最近修改时间,由服务器告诉浏览器。 当客户端第一次请求服务器时,服务端会返回一个 Last-Modified 响应头,该字段是一个标准时间。客户端请求服务器的时候会带上 If-Modified-Since 请求头字段,该字段的值就是服务器返回的 Last-Modified 的值。服务器接收到请求后会比较这两个值是否一样,一样就返回 304,让客户端从缓存中读取,不一样就会返回新文件给客户端并更新 Last-Modified 响应头字段的值。If-None-Match
: 请求头,缓存资源标识,由浏览器告诉服务器。其实就是第一次访问服务端返回的 Etag 的值。Etag
: 响应头,资源标识,由服务器告诉浏览器。 为了解决文件修改时间只能精确到秒的问题,引入 Etag 响应头。Etag 是由文件修改时间与文件大小计算而成,只有当文件文件内容或修改时间变了 Etag 的值才会发生变化。当客户端第一次请求服务器的时候,服务端会返回一个 Etag 响应头。客户端请求服务器的时候会带上 If-None-Match 请求头字段,该字段的值就是服务器返回的 Etag 的值。服务器接收到请求后会比较这两个值是否一样,一样就返回 304,让客户端从缓存中读取,不一样就会返回新文件给客户端并更新 Etag 响应头字段的值。
代码拆分 + 动态导入
对不常变动的资源单独打包,如使用 webpack 的 代码分离。
图片等资源懒加载
服务端渲染(SSR)
客户端渲染(CSR)
:CSR 是 Client Side Render 简称;页面上的内容是我们运行 js 文件生成的,服务端返回的 html 只是一个模板。服务端渲染(SSR)
是 Server Side Render 简称;页面上的内容是通过服务端渲染生成的,浏览器直接显示服务端返回的 html 就可以了。
渐进式 Web 应用:PWA
代码执行
防抖与节流(减少代码执行次数)
防抖
:指触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数开始执行时间。
节流
:指事件在 n 秒内只执行一次,若在 n 秒内重复触发,只会执行一次
耗时任务拆分
浏览器空闲时执行:requestIdleCallback
Worker 多线程加速
Wasm 加速
页面渲染
减少回流(Reflow)和重绘(Repaint)
回流
:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)
重绘
:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式。这个过程叫做重绘。
虚拟列表
只渲染可视区域;