5

请求过程中一些潜在的性能优化点

深入理解http请求的过程是前端性能优化的核心!

  • dns是否可以通过缓存减少dns查询时间?
  • 网络请求的过程走最近的网络环境?
  • 相同的静态资源是否可以缓存?
  • 能否减少请求http请求大小?
  • 减少http请求数量
  • 服务端渲染

DNS解析过程

clipboard.png

服务器端请求处理

clipboard.png

HTTP状态码

clipboard.png

注意:

1、文件合并存在的问题。

  • 首屏渲染问题(公共库合并)
  • 缓存失效问题(不同页面的合并)

2、资源的合并与压缩(html,css,js压缩和混乱,文件合并,开启gzip)。

  • 目的1:减少请求http请求大小
  • 目的2:减少http请求数量

图片相关的优化的核心概念

png8/png24/png32之间的区别?

  • png8 --- 2^8(256)色 + 支持透明
  • png24 --- 2^24色 + 不支持透明
  • png32 --- 2^24色 + 支持透明

不同格式图片的特点和常用的业务场景?

  • jpg有损压缩,压缩率高,不支持透明(不需要透明图片的的业务场景)
  • png支持透明,浏览器兼容性好(需要透明图片的业务场景)
  • webp压缩程度更好,在ios webview中有兼容性问题(安卓全部)
  • svg矢量图,代码内嵌,相对较小(图片样式相对简单的场景)

对图片的优化有哪些?

  • 对图片进行压缩png24->png8(可以使用:https://tinypng.com/
  • CSS雪碧图(可以使用用这个网站生成雪碧图相关的css代码:http://www.spritecow.com
  • Image inline(base64编码)
  • 使用矢量图

css、js加载与执行(考虑优化点)

clipboard.png

HTMLParser解析器自上而下解析,生成DOM树。
外部资源link、script,浏览器会发起请求。
解析CSS生成CSS规则树,进而构建渲染树(计算element位置,布局layout)。
接着调用操作系统NativeGUI的API进行绘制。

浏览器渲染页面

clipboard.png

HTML渲染过程的一些特点

  • 顺序执行、并发加载

外部资源并发请求,一个域名下的并发请求数是有上限的。
所以一般将网站的静态资源托管在多个CDN下。

  • css阻塞

css在head中可以阻塞页面渲染、css可以阻塞js执行,但是css不阻塞外部脚本的加载。

  • js阻塞

直接引入的js阻塞页面的渲染(asyn[异步下载、立即执行]、differ[并行下载、顺序执行]这两种方式加载js例外)

js不阻塞资源的加载(预资源加载器)

js顺序执行,阻塞后续js逻辑的执行(单线程)

懒加载、预加载

懒加载:图片进入可视区域之后请求图片资源。
懒加载的实现:
1.JS判断图片是否进入可视区域。
2.当进入时,修改img的src属性为实际图片地址。

预加载:图片等静态资源在使用之前提前请求。
预加载实现:
1.使用标签(<img src="xxx" style="display:none">)
2.使用Image对象(new Image();)
3.使用XMLHTTPRequest对象(资源跨域问题)

回流与重绘

UI线程和js线程互斥。
css性能能让JavaScript变慢。
频繁触发重绘回流,会导致UI频繁渲染,最终导致js变慢。

回流: render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,
这就称为回流(reflow)。

  • 页面渲染初始化
  • 盒子模型相关属性变化
  • 窗口resize事件触发
  • DOM结构变化,比如删除了某个节点
  • 获取某些属性,引发回流 很多浏览器会对回流做优化,他会等到足够数量的变化发生,在做一次批处理回流。 但是除了render树的直接变化。

获取以下属性时会引发回流
width,height
offsetTop/Left/Width/Height
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
调用了getComputedStyle(), 或者 IE的 currentStyle

重绘: render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会
影响布局的,比如background-color,这就称为重绘。

Chrome中满足以下任意情况就会创建图层:

video、canvas都是一个独立的图层。

  • 3D或透视变换(perspective transform)CSS属性
  • 使用加速视频解码的<video>节点
  • 拥有3D(WebGL)上下文或加速的2D上下文的<canvas>节点
  • 混合插件(如Flash)
  • 对自己的opacity做CSS动画或使用一个动画webkit变换的元素
  • 拥有加速CSS过滤器的元素
  • 元素有一个包含复合层的后代节点(一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

常用的会独立为一个图层的属性:
transform:translateZ(0);
will-change:transform;

怎么优化呢?

  • 将频繁重绘回流的DOM元素单独作为一个独立图层,那么这个DOM元素重绘和回流的影响只会在这个图层中。(但是:浏览器图层合成也会花比较多的时间,所以,是否新建图层得看实际情况,具体问题,具体分析。)
  • translate(改变不会触发浏览器重新布局,但是元素仍会占据原始位置)替代top(会触发重新布局)改变。
  • opacity(不会触发重绘)替代visibility(会触发重绘)。
  • 不要一条一条地修改DOM的样式,预先定义好class,然后修改DOM的className
  • 把DOM离线后修改。(eg:先把DOM给display:none,然后修改100次,再把它显示出来。)
  • 不要把DOM节点的属性值放在一个循环里当成循环里的变量(offsetHeight、offsetWidth)
  • 不要使用table布局,一个小的改动会造成整个table的重新布局。
  • 对动画新建图层。
  • 启用GPU硬件加速。(transform:translate3d(0,0,0)、transform:translateZ(0))

浏览器存储

Cookie相关

Cookie 因为HTTP请求无状态,所以需要cookie去维护客户端状态。

cookie的生成方式:

  • 1.http response header中的 set-cookie(服务端生成,客户端保存)
  • 2.js中可以通过document.cookie可以读写cookie(客户端自身数据的存储)

cookie存储的限制:

  • 1.作为浏览器端存储,大小4kb左右
  • 2.需要设置过期时间`expire

对于cookie的优化:

cookie中在相关域名下面--cdn的流量损耗
解决方法:__ cdn的域名和主站的域名要分开 __

对于cookie的读写操作:

// 写入
document.cookie = "username=hello";
// 读取
let cookie = document.cookie;
/**
  * param [String] cookie
  * return [Object] object
  */
function getCookie(cookie){
    if(!cookie){ return null; }
    let reg = /\s*([^;]+)\s*=\s*([^;]+)\s*/g;
    let obj = {};
    cookie.replace(reg,($0,$1,$2) => {
        if($1&&$2){
            obj[$1] = $2;
        }
    });
    return obj;
}

cookie存储数据能力被localstorage替代。
httponly :不允许js读写。(防止盗用cookie)

LocalStorage相关

  • HTML5设计出来专门用于浏览器存储的
  • 大小为5M左右
  • 仅在客户端使用,不和服务器进行通信
  • 接口封装较好
  • 浏览器本地缓存方案

对于LocalStorage的读写操作:

// 写入
localStorage.setItem('username','hello')
undefined
// 读取
localStorage.getItem('username')
"hello"

SessionStorage相关

  • 会话级别的浏览器存储
  • 大小为5M左右
  • 仅在客户端使用,不和服务器进行通信
  • 接口封装较好
  • 对于表单信息的维护(多页表单数据的维护)

对于 SessionStorage的读写操作:

// 写入
 SessionStorage.setItem('username','hello')
undefined
// 读取
 SessionStorage.getItem('username')
"hello"

IndexedDB(用的比较少)

  • IndexedDB是一种低级API,用于客户端存储大量结构化数据。
  • 为应用创建离线版本

PWA相关

  • 可靠:在没有网络的环境下也能提供基本的页面访问,而不会出现“未连接到互联网”的页面。
  • 快速:针对网页渲染及网络数据访问有较好优化。
  • 融入(Engaging):应用可以被增加到手机桌面,并且和普通应用一样有全屏、推送等特性。

具体内容查看笔记:

ServiceWorker探索
ServiceWorker和cacheStorage缓存及离线开发

利用ServiceWorker进行多页面通信:

// 主页面发送信息
navigator.serviceWorker.controller.postMessage(value);
// 主页面监听消息
navigator.serviceWorker.addEventListener('message',event => {
    // console.log(event.data);
});

// ServiceWorker接收信息(对其他页面消息分发)
self.addEventListener('message',event => {
    let promise = self.clients.matchAll().then(clientList => {
        let senderID = event.source ? event.source : 'unknown';
        clientList.forEach(client => {
            if(client.id === senderID){
                return;
            }
            client.postMessage({
                client: senderID,
                message: event.data
            });
        });
    });
    event.waitUntil(promise);    
});

浏览器缓存

Cache-Control

clipboard.png

  • max-age 当小于缓存时间时,直接加载本地资源(from memory cache),expires(到期时间http/1.0)和max-age相比,max-age具有更高的优先级。
  • s-maxage 共享缓存,public相关的缓存设备例如CDN,优先级高于max-age,如果客户端访问到的是CDN服务器缓存中的数据切未更改则返回304状态码。(Cache-control:max-age=3600, s-maxage=31536000,就算在max-age时间内,也不直接加载本地文件,而是访问CDN缓存。缓存中的文件如果没有更改,则直接通知客户端304,加载本地文件。感觉和no-cache很像呀)
  • no-cache (例如:Cache-Control:private, max-age=0, no-cache),不是不缓存的意思,它实际上的机制是,仍然对资源使用缓存,但每一次在使用缓存之前必须(MUST)向服务器对缓存资源进行验证。
  • no-store 对该文件不适用任何缓存策略。
  • public 资源将被客户端和代理服务器缓存。
  • private 资源仅被客户端缓存,代理服务器不缓存。
  • public VS private 要知道从服务器到浏览器之间并非只有浏览器能够对资源进行缓存,服务器的返回可能会经过一些中间(intermediate)服务器甚至甚至专业的中间缓存服务器,还有CDN。而有些请求返回是用户级别、是私人的,所以你可能不希望这些中间服务器缓存返回。此时你需要将Cache-Control设置为private以避免暴露。

Expires

Expires是http/1.0中定义的浏览器缓存策略。(expires: Wed, 24 Jan 2018 12:19:34 GMT

  • 用来指定资源到期的时间,是服务器端的具体的时间点。
  • 告诉浏览器在过期时间前可以直接从缓存取数据,而无需再次请求。

Last-Modified/If-Modified-Since

  • 基于客户端和服务端协商的缓存机制
  • last-modified —— response header
  • if-modified-since —— request header
  • 需要与cache-control共同使用

但是last-modified是有缺点的。

  • 1.某些服务器不能获取精确的修改时间
  • 文件修改时间改了,单文件内容却没有变

Etag/If-None-Match

此缓存策略优先级高于Last-Modified/If-Modified-Since
clipboard.png

  • 文件内容的hash值
  • etag —— response header
  • if-none-Match —— request header
  • 需要与cache-controlgongt使用

总体缓存流程图

clipboard.png

服务器端性能

vue渲染遇到的问题

vue执行过程:
下载vue.js ==> 执行vue.js代码 ==> 生成HTML页面

随着前端浏览器的性能的提升,大量的运算在前端执行。
使用vue框架出现了首屏性能、渲染问题。

优化方案?

  • 构建层模板编译(在构建层做模板编译工作,将模板语法编译成在vueruntime中可以直接执行的js代码)
  • 数据无关的prerender的方式(将vue渲染完成的静态页面返回)
  • 服务端渲染

五月花开
1.3k 声望878 粉丝

仰望星空,也要脚踏实地。