前端性能优化
2019-04-28 本文已影响19人
alanwhy
涉及层面
- 网络层面
- 构建层面
- 浏览器渲染层面
- 服务端层面
资源合并与压缩
http请求的过程及潜在的性能优化点
浏览器的一个请求从发送到返回都经历了什么
image.png
- dns是否可以通过缓存减少dns查询时间
- 网络请求的过程走最近的网络环境
- 相同的静态资源是否可以缓存
- 能否减少http请求大小
- 能否减少http请求数量
- 服务端渲染
html压缩
HTML代码压缩就是压缩这些在文本文件中有意义,但是在HTML中不显示的字符,包括空格,制表符,换行符等,还有一些其他意义的字符,如HTML注释也可以被压缩
- 使用在线网站进行压缩(走构建工具多,公司级在线网站手动压缩小)
- node.js提供了html-minifier工具
- 后端模板引擎渲染压缩
css及js压缩
- 使用在线网站进行压缩
- 使用html-minifier对html中的css进行压缩
- 使用clean-css对css进行压缩
- 使用html-minifier对html中的js进行压缩
- 使用uglifyjs2对js进行压缩
不合并文件可能存在的问题
image.png- 使用在线网站进行合并
- 构建阶段,使用nodejs进行文件合并
图片相关优化
不同的格式图片常用的业务场景
- jpg有损压缩,压缩率高,不支持透明。大部分不需要透明图片的业务场景
- png支持透明,浏览器兼容性好。大部分需要透明图片的业务场景
- webp压缩程度更好,在ios webview中有兼容性问题。android全部(解码速度和压缩率高于jpg和png,但是ios safari还没支持)
- svg矢量图,代码内嵌,相对较小,图片样式相对简单的场景(尽量使用,绘制能力有限,图片简单用的比较多)。图片样式相对简单的业务场景
图片压缩的几种情况
- 针对真实图片情况,舍弃一些相对无关紧要的色彩信息
- CSS雪碧图:把你的网站用到的一些图片整合到一张单独的图片中
- Image-inline:将图片的内容嵌到html中(减少网站的HTTP请求)
- 使用矢量图
- 在android下使用webp
css和js的装载与执行
HTML页面加载渲染的过程
image.png
- 顺序执行,并发加载
- 词法分析:从上到下依次解析
- 通过HTML生成Token对象(当前节点的所有子节点生成后,才会通过next token获取到当前节点的兄弟节点),最终生成Dom Tree
- 并发加载:资源请求是并发请求的
- 并发上限
- 浏览器中可以支持并发请求,不同浏览器所支持的并发数量不同(以域名划分),以Chrome为例,并发上限为6个
- 词法分析:从上到下依次解析
- 是否阻塞
- css阻塞
- css 在head中通过link引入会阻塞页面的渲染
- 如果我们把css代码放在head中去引入的话,那么我们整个页面的渲染实际上就会等待head中css加载并生成css树,最终和DOM整合生成RanderTree之后才会进行渲染
- 为了浏览器的渲染,能让页面显示的时候视觉上更好。
优化点: 把CDN资源分布在多个域名下
- css 在head中通过link引入会阻塞页面的渲染
- css阻塞
懒加载与预加载
懒加载
- 图片进入可视区域之后请求图片资源
- 对于电商等图片很多,页面很长的业务场景适用
- 减少无效资源的加载
- 并发加载的资源过多会阻塞js的加载,影响网站的正常使用
先将img标签中的src链接设为同一张图片(空白图片),将其真正的图片地址存储再img标签的自定义属性中(比如data-src)。当js监听到该图片元素进入可视窗口时,即将自定义属性中的地址存储到src属性中,达到懒加载的效果。
var viewheight = document.documentElement.clientHeight //可视区域高度
function lazyload(){
var eles = document.querySelectorAll('img[data-original][lazyload]')
Array.prototype.forEach.call(eles,function(item,index){
var rect;
if(item.dataset.original === '') return;
rect = item.getBoundingClientRect(); //返回元素的大小及其相对于视口的
if(rect.bottom >= 0 && rect.top < viewheight){
!function(){
var img = new Image();
img.src = item.dataset.url;
img.onload = function(){
item.src = img.src
}
item.removeAttribute('data-original');
item.removeAttribute('lazyload');
}()
}
})
}
预加载
- 图片等静态资源在使用之前的提前请求
- 资源使用到时能从缓存中加载,提升用户体验
- 页面展示的依赖关系维护
第一种方式:直接请求下来
<img src="https://user-gold-cdn.xitu.io/2019/2/21/1690d1b216cbfa18" style="display: none"/>
<img src="https://user-gold-cdn.xitu.io/2019/2/21/1690d1b21b70c8d2" style="display: none"/>
<img src="https://user-gold-cdn.xitu.io/2019/2/21/1690d1b216e17e26" style="display: none"/>
<img src="https://user-gold-cdn.xitu.io/2019/2/21/1690d1b217b3ae59" style="display: none"/>
第二种方式:image对象
var image = new Image();
image.src = "www.pic26.com/dafdafd/safdas.jpg";
第三种方式:xmlhttprequest
var xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.onreadystatechange = callback;
xmlhttprequest.onprogress = progressCallback;
xmlhttprequest.open("GET","http:www.xxx.com",true);
xmlhttprequest.send();
function callback(){
if(xmlhttprequest.readyState == 4 && xmlhttprequest.status == 200){
var responseText = xmlhttprequest.responseText;
}else{
console.log("Request was unsuccessful:" + xmlhttprequest.status);
}
}
function progressCallback(){
e = e || event;
if(e.lengthComputable){
console.log("Received"+e.loaded+"of"+e.total+"bytes")
}
}
重绘与回流
回流
- 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就成为回流(reflow)
- 当页面布局和几何属性改变时,就需要回流
重绘
- 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不影响布局,比如background-color。
回流必将引起重绘,但是重绘不一定会引起回流
新建DOM的过程
- 获取DOM后分割为多个图层
- 对每个图层的节点计算样式结果(Recalculate style 样式重计算)
- 为每个节点生成图形和位置(Layout 回流和重布局)
- 将每个节点绘制填充到图层位图中(Paint Setup和Paint 重绘)
- 图层作为纹理上传至gpu
- 符合多个图层到页面上生成最终屏幕图像(Composite Layers 图层重组)
优化方式:
- 尽量避免使用触发回流、重绘的CSS属性
- 将重绘、回流的影响范围限制在单独的图层(layers)之内
- 图层合成过程中消耗很大页面性能,这时候需要平衡考虑重绘回流的性能消耗
浏览器存储
cookies
cookie的生成方式:
- http-->response header-->set-cookie
- js中可以通过document.cookie可以读写cookie
cookie的限制:
- 作为浏览器存储,大小4kb左右
- 需要设置过期时间 expire
localStorage
- HTML5设计出来专门用于浏览器存储的
- 大小为5M左右
- 仅在客户端使用,不和服务端进行通信
- 接口封装较好
- 浏览器本地缓存方案
sessionstorage
- 会话级别的浏览器存储
- 大小为5M左右
- 仅在客户端使用,不和服务器端进行通信
- 接口封装较好
- 对于表单信息的维护
indexedDB
- IndexedDB是一种低级API,用于客户端存储大量结构化数据。该API使用索引来实现对该数据的高性能搜索。
- 为应用创建离线版本
function openDB(name, callback) {
//建立打开indexdb indexedDB.open
var request = window.indexedDB.open(name)
request.onerror = function(e) {
console.log('on indexedDB error')
}
request.onsuccess = function(e) {
myDB.db = e.target.result
callback && callback()
}
//from no database to first version,first version to second version...
request.onupgradeneeded = function() {
console.log('created')
var store = request.result.createObjectStore('books', {
keyPath: 'isbn'
})
console.log(store)
var titleIndex = store.createIndex('by_title', 'title', {
unique: true
})
var authorIndex = store.createIndex('by_author', 'author')
store.put({
title: 'quarry memories',
author: 'fred',
isbn: 123456
})
store.put({
title: 'dafd memories',
author: 'frdfaded',
isbn: 12345
})
store.put({
title: 'dafd medafdadmories',
author: 'frdfdsafdafded',
isbn: 12345434
})
}
}
var myDB = {
name: 'tesDB',
version: '2.0.1',
db: null
}
function addData(db, storeName) {
}
openDB(myDB.name, function() {
// myDB.db = e.target.result
// window.indexedDB.deleteDatabase(myDB.name)
});
//删除indexedDB
缓存
期望大规模数据能自动化缓存,而不是手动进行缓存,需要浏览器端和服务器端协商一种缓存机制
- Cache-Control所控制的缓存策略
- last-modified 和 etage以及整个服务端浏览器端的缓存流程
- 基于node实践以上缓存方式
image.png
服务端性能优化
服务端用的node.js因为和前端用的同一种语言,可以利用服务端运算能力来进行相关的运算而减少前端的运算
image.png
原文链接:web前端性能优化总结