资源的合并与压缩
- 核心:减少http请求数量(合并)减少资源请求大小(压缩)
- html压缩:压缩这些在文本文件中有意义,但是在html中不显示的字符,包括空格,制表符,换行符等,还有一些其他意义的字符,如注释等也可以被压缩。
- 使用在线网站进行压缩(现在不常用)
- nodejs提供的 html-minifier 工具(可选是否压缩注释,是否压缩空格等)
- 后端模版引擎渲染压缩
- css压缩(无效代码删除,css语义合并)
- 使用在线网站进行压缩
- 使用的 html-minifier 对 html 中对 css 压缩
- 使用 clean-css 对 css 压缩
- js压缩与混乱(无效字符的删除,剔除注释,代码语义的缩减和优化,代码保护)
- 使用在线网站进行压缩
- 使用的 html-minifier 对 html 中对 js 压缩
- 使用 uglifyjs2 对 js 压缩
- 文件合并
- 不合并时
- 文件与文件之间有插入的上行请求,增加了N-1个网络延迟。
- 受丢包问题影响严重。
- keep-alive经过代理服务器时可能会被打断。
- 合并时
- 首屏渲染问题。
- 缓存失效问题。
- 结局方案:
- 公共库单独合并与业务代码分开。
- 不同页面分别打包(异步加载组件)
- 见机行事,随机应变
- 如何进行文件合并?
- 使用在线网站进行文件合并
- 使用nodejs实现文件合并(gulp webpack fis3)
- 不合并时
图片相关优化
- 各图片格式对比:
- jpg: 有损压缩 压缩率高 体积小 加载快 不支持透明(大部分不需要透明图片的业务场景比如大的背景图或轮播图等)
- png: 无损压缩 体积大 质量高 浏览器兼容好 (颜色简单,需要透明图片,对比性强的小图片)
- png8 -> 256色 支持透明
- png24 -> 2^24色 不支持透明
- png32 -> 2^24色 支持透明
- webp 由谷歌2010提出 压缩格式更好 在ios webview内有兼容问题,安卓没问题;优势在于它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式,Alpha透明以及动画的特性,在JPEG和PNG上的转换效果都非常优秀稳定和统一。
- SVG(可缩放矢量图形)文本文件内嵌在代码中,体积更小 可以无限放大不失真 兼容性好 图片样式相对简单(例:iconfont)
- Base64
- 文本文件 依赖代码 小图片的最优解决方案 作为雪碧图的补充而存在
- Base64是一种用于传输8Bit字节码的编码形式,将图片通过Base64编译,可将编码结果直接写入html或css从而减少HTTP的请求。
- 使用条件:1. 图片的实际尺寸小,更新频率低无法以雪碧图等形式与其他小图融合。
- css雪碧图:优:通过图片整合减少HTTP请求;缺:整合图片过大时,一次加载过慢或请求失败时,会导致页面失常(可以根据业务场景拆分整合为多张雪碧图,移动端使用较少)。
CSS JS的加载与执行
-
一个网站在浏览器端是如何被渲染的?
页面加载渲染过程.png -
HTML渲染过程特点:
- 顺序执行(自上而下) 并发加载(浏览器对域名的加载数量有限制)
- 是否阻塞
- CSS阻塞
- CSS在head中以link形式引入会阻塞页面的渲染,需等link标签所引入的CSS加载后,方进行渲染。
- CSS会阻塞JS的执行(JS执行可能会依赖已经生成好CSS的DOM)。
- CSS不阻塞外部脚本加载。
- CSS加载方式
- link 2. @import 3. 行内样式 4. 内部样式表
- link与@import的区别:
- link功能更多,可以定义RSS,Rel等,@import只能加载CSS。
- 解析link时,页面会同步加载css。@import所引用的只能等页面加载完成后加载。
- @import需要IE5以上
- link可以JS引入。@import不可
- CSS选择器优先级
- !important > 行内 > id > class >tag > * > 继承 > 默认
- 从右向左解析
- 约具体优先级越高,后面的会覆盖前面的
- CSS书写顺序:位置属性 > 大小 > 文字系列 > 背景边框 > 其他
- JS阻塞
- <script>直接引入会阻塞页面的渲染(JS执行可能会改变现有页面结构)。
- JS不会阻塞资源的加载。
- JS顺序执行,阻塞后续JS逻辑的执行。
- defer属性:
- 延迟脚本执行,DOM加载完成后再执行脚本。
- 非外部引入的内置<script>标签defer属性不生效,也不应该在外部脚本中使用document.write
- async属性:
- 使用另一个进程下载脚本,下载时不会阻塞渲染,脚本下载完毕后暂停解析HTML,执行该脚本,脚本执行完毕后恢复解析HTML。
- 当同时多个外部脚本加载时,无法保障执行顺序,哪个先下载完成就先执行哪个。
- 脚本直接无依赖关系就使用async,反之用defer。
- 同时使用async与defer时,defer不起作用,由async决定。
- CSS阻塞
- 依赖关系
- 引入方式
懒加载与预加载
-
懒加载:
- 图片进入可视区域之后请求图片资源。
- 适用于电商等图片很多,页面很长的业务场景。
- 可以有效的减少无效资源的加载。
- 并发记载的资源过多会阻塞js加载,影响网站的正常使用。
/**HTML部分**/ <img src="" class="image-item" lazyload="true" data-original="图片路径"/> /**JS部分**/ //获取可是区域的高度 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 } //getBoundingClientRect:返回元素的大小及其相对于视口的位置。 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") }() } } } //手动调用,使第一屏图片正常显示 lazyload() document.addEventListener('scroll', lazyload) //需要预先设置图片高度占位,如果图片没有预设高度,每个img的hight几乎为零,会导致首屏可是区域图片过多。
-
预加载
- 图片等静态资源在使用之前的提前请求。
- 资源被需要时可以从缓存中加载,提升用户体验。
- 页面展示的依赖关系维护。
//解决方案1:使用Image对象 var image = new Image() image.src = "图片地址" //解决方案2:使用XMLHttpRequest对象 //优:对整个请求过程有更好的监控,可以更好的控制传输过程。 //缺:存在跨域问题 //解决方案3:使用preload.js
重绘与回流
- 页面渲染方式:
- 服务器渲染(所见即所得-页面呈现的内容我们在html源文件可以找到)
- 客户端渲染(页面呈现的内容,在html源文件找不到)
- 浏览器内核:1. 渲染引擎(HTML解释器,CSS解释器,布局,网络,存储等) 2. JS引擎
- 浏览器渲染
- HTML解释器(将HTML文档经过语法分析输出DOM树)
- CSS解释器 (解析CSS文档 生成样式规则)
- 图布局层计算模式(布局计算每个对象的精确位置与大小)
- 视图绘制模式(进行具体节点的图像绘制,将像素渲染在屏幕上)
- JavaScript引擎(编译执行JavaScript代码)
- 回流: 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流(reflow),当页面 布局 和 几何属性 改变时就需要回流。
- 触发页面重新布局的属性
- 盒子模型相关属性(width,height, padding, margin, display, border-width,border, min-height )
- 定位属性及浮动(top, bottom, left, right, position, float, clear)
- 改变节点内部文字结构(text-align, overflow-y, font-weight, overflow, font-family, line-height, vertival-align, white-space, font-size)
- 触发页面重新布局的属性
- 重绘 :当render tree中的一些元素需要更新属性,而这些属性只影响元素的外观,风格,而不影响布局的,称之为重绘(background-color,color)
- ==回流必定引起重绘,重绘不一定会引起回流==
- 新建DOM的过程
- 获取DOM后分割为多个图层
- 对每个涂层对节点计算样式结果
- 为每个节点生成图形和位置(Layout-回流和重新布局)
- 将每个节点绘制填充到图层位图中
- 将图层作为纹理上传到CPU
- 复合多个图层到页面上生成最终屏幕图像
- 将 频繁重绘回流++ 的DOM元素单独作为一个 独立图层,那么这个DOM元素的重绘和回流的影响 只会在这个图层中。
- 生成新图层
- 3D或者透视变化CSS属性(translated 3d,translateZ)
- 使用加速视频解码的video标签,iframe标签
- 拥有3D(WebGL)上下文或者加速的2D上下文<canvas>
- 混合插件(flash)
- 使用动画的元素(opacity)
- 元素有一个包含符合层的后代节点
- 该元素在符合层上渲染,z-index较低,有兄弟节点
- 优化点:
- 用 translate 代替 top。
- 用 opacity 替换 visibility,使用visibility替换display:none。
- 不要一条一条修改DOM的样式,预先定义好class,然后修改DOM的className。
- DOM离线后修改(先display:none,修改完成后再显示)。
- 不要把DOM节点的属性值(offsetHeight,offsetWidth)放在循环里当循环的变量。
- 不使用table。
- 动画实现速度的选择,速度越快回流次数越多。
- 将频繁运行的动画变为图层,图层可以阻止节点回流影响别的元素。
- 启用GPU加速
浏览器存储
- Cookie:(HTTP请求无状态,所以需要cookie去维持客户端状态)
- 生成方式:
- http response header 中的 set-cookie。
- js中document.cookie 可以读写cookie。
- 服务端生成,客户端存储与管理,存储上限4KB。
- 以域名的形式进行区分,不同域名下的cookie是独立的。可以设置生效的域,可以操作Cookie是当前域及当前域下的所有子域,一个域名上限20条。
- 使用场景:
- 会话状态管理,(登录状态,购物车)
- 个性化设置(自定义设置,主题)
- 浏览器行为跟踪
- 浏览器端和服务器端交互。
- 客户端自身数据存储。
- 属性:1. expire 过期时间 2. httponly禁止JS读写
- Cookie在相关域名下存在CDN的流量损耗(解决办法:CDN的域名和主站域名分开)
- 生成方式:
- LocalStorage(专职浏览器存储;5M左右; 仅在客户端使用,不与服务端通信; 接口封装较好; 浏览器本地缓存方案)
- SessionStorage(会话级别的浏览器存储;5M左右; 仅在客户端使用,不与服务端通信; 接口封装较好; 对于表单信息的维护)
- IndexedDB(是一种低级API,用于客户端存储大量结构化数据,该API使用索引来实现对该数据的高性能搜索,虽然WebStorage对于存储较少量的数据很有用,但对于存储更大量的数据化结构来说,这个方法不太有用,IndexedDB提供了一个解决方案。可以为应用创建离线版本)
- PWA(Web App新模型,渐进式Web App,通过一系列新的Web特性,配合优秀的UI交互设计,逐步的增强Web App的用户体验)
- 可靠性:在没有网络的环境下也能提供基本的页面访问,为不会出现“未链接到互联网”的页面。
- 快速:针对网络渲染和网络数据访问有较好优化。
- 融入:应用可以被增加到手机桌面,并且和普通应用一样有全屏,推送等特性。
- 性能检测-lighthouse 谷歌插件
- Service Worker:一个脚本,浏览器独立于当前页面,将其在后台运行,为实现一些不依赖页面或者用户交互的特性打开了一扇大门。在未来这些特性将包括推送信息,背景后台同步,geofencing(地理围栏定位),但它将推出的第一个首要特性,就是拦截和处理网络请求的能力,包括以编程方式来管理被缓存的响应。
浏览器缓存
-
httpheader中的Cache-Control(Response,Request)
- max-age:最大缓存时间
- 在HTTP1.1被提出;
- max-age:31536000;
- status Code:200;
- 在这段时间内浏览器不会再向服务器发送请求。
- s-maxage:最大缓存时间
- status Code:304;
- 只对public缓存设备(CDN)生效;
- 同时出现时优先级高于max-age,若s-maxage未过期则向代理服务器请求缓存资源;
- s-maxage:31536000;
- private:只能被浏览器缓存(默认)
- public:可以被代理服务器与浏览器缓存(未明确设置public 但使用了s-maxage也表示可以被代理服务器缓存)
- no-cache:绕开浏览器,每次请求不会询问浏览器缓存直接与服务器通信确认资源是否过期(Cache-Control:private,max-age=0,no-cache)
- no-store:不使用任何缓存策略。
- max-age:最大缓存时间
-
Expires:(HTTP1.0版本有效)缓存过期时间;用来指定资源的到期时间,是服务器端的具体时间点,告诉浏览器在过期时间之前可以直接从浏览器缓存取数据,无需再次请求。
- expires:Wed, 24 Jun 2018 12:19:34 GMT
- 优先级:Cache-Control > Expires 同时存在以Cache-Control为准
- 会存在时间戳问题,此属性对本地时间有依赖,若修改客户端时间会失效。
-
Last-Modified/If-Modified-Since(基于客户端和服务端协商的缓存机制)
- If-Modified-Since 资源文件的最后的修改时间:在request header上 ;若资源没有更新,status Code:304;
- Last-Modified 资源最后修改时间:存在response header中
- 与Cache-Control配合使用。
- Last-Modified缺点:
- 某些服务器不能获取精确的修改时间。
- 有可能文件的修改时间改了,但是文件内容没有更改。
-
Etag/If-None-Match(文件内容的hash值)
- Etag存在response header中
- If-None-Match存在request header中
- 两者相比较有变化status Code:200,没变化status Code:304
- 比Last-Modified/If-Modified-Since更精确,优先级更高。
- 与Cache-Control配合使用。
-
分级缓存策略
- 200状态(form cache):由expires/cache-control控制控制。1. expires绝对时间,cache-control相对时间,两者存在时cache-control覆盖expires,只要没有失效,浏览器只访问自己的缓存。
- 304状态:由Last-Modified/Etag控制,协商缓存情况。
- 200状态:没有缓存或者协议缓存失效,浏览器直接去服务器下载更新数据
-
缓存流程图
缓存过程.png -
Cache-control流程图
cache-control.png
服务端性能优化
- VUE渲染面临的问题-首屏渲染
- 构建层模版编译。
- 对无关数据进行prerender
- 服务端渲染
网友评论