浏览器是怎样解析CSS 选择器的?
浏览器会从右向左解析CSS 选择器,我们知道DOM Tree
与Style Rule
合称为 布局树,实际上是需要将Style Rule
附着到 布局树上,因此需要根据选择器提供的信息对DOM Tree
进行遍历,这样才能将 样式附着到对应的DOM元素上例子
1
2
3.mod-nav h3 span {
font-size: 16px
}1
2
3
4
5
6
7
8
9
10
11
12
13
14<div class="mod-nav">
<header>
<h3>
<span>header</span>
</h3>
</header>
<div>
<ul>
<li><a>1</a></li>
<li>11</li>
<li>11</li>
</ul>
</div>
</div>若从左向右的匹配,过程是
从class=”mod-nav”,遍历子节点header 和 子节点 div
然后各自向子节点遍历,在右侧div的分支中,最后需要遍历到 叶子节点a,发现不符合规则,需要回溯到ul节点,再遍历下一个 li-a, 一棵DOM树的节点动不动就上千,这种效率很低
如果从右向左的匹配先找到所有的最右节点span ,对于每一个span ,向上寻找节点 h3
由h3再向上寻找class=mod-nav 的节点
最后找到根元素html则结束这个分支的遍历
后者匹配性能更好,是因为从右向左 的匹配在第一步就筛掉了大量的不符合条件的最右节点;而从左向右的匹配规则的性能都浪费在了失败的查找上面
谈谈浏览器的JS 引擎
- Chrome:使用
V8
引擎 - safari: 使用
JavaScriptCore
引擎 - Firefox: 使用
SpiderMonkey
引擎 - Edge: 使用的是
Chakra
引擎
- Chrome:使用
浏览器渲染主流程:见其他
从页面输入URL 到底发生了什么:见其他
cookies,sessionStorage 和 localStorage 的 区别?
相同点: 都是保存在浏览器端,且都是同源的
不同点:从cookies 是为了 标示用户身份而存储在用户本地终端上的数据,始终在同源http 请求中携带,
即cookies在浏览器和服务器之间来回传递,而sessionstorage和localstorage不会自动把数据发给服务器
仅保存在本地存储大小的限制不一样:cookie 保存的数据很小,不能超过 每个4K,不超过300,而 sessionstorage和 localstorage保存的数据很大,5M
数据有效期不一样,
cookie 在设置 的cookie 过期 时间之前一直有效,即使窗口或者浏览器关闭,
sessionstorage仅在浏览器窗口关闭之前有效
localstorage始终有效,窗口和浏览器关闭也一直保存,长久数据存储作用域不一样
cookie 在所有的同源窗口都是共享的
sessionstorage: sessionStorage 存储的数据只有在同一个会话中的页面才能访问,当页面关闭或者浏览器关闭是后,session中的数据也会销毁
localstorage在所有同源窗口是共享的
浏览器的回流和重绘
在讨论回流与重绘之前,我们要知道- 浏览器使用流式布局
- 浏览器会把
HTML
解析成DOM
,把CSS 解析成CSSOM
,DOM
和CSSOM
合并产生了布局树(Render Tree) - 有了布局树,我们知道了所有节点的样式,然后计算他们在 页面上的大小和位置,最后把节点绘制在页面上
- 由于浏览器 使用流 式 布局,对 布局树的计算 通常 只需要 遍历一次就可以了,但是table 以及 其 内部元素除外,可能需要多次计算,这也是为什么要避免使用table 原因
当布局树中部分或者全部元素的尺寸、结构或者某些属性发生改变时候,浏览器重新渲染部分或者全部文档的过程称为回流
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的
DOM
元素 - 激活CSS 伪类
- 查询某些属性或者调用哪些方法
一些常用而且会导致回流的属性和方法
- clientWidth clientHeight clientTop clientLeft
- offsetWidth offsetHeight offsetTop offsetLeft
- scrollWidth scrollHeight scrollTop scrollLeft
- scrollIntoView scrollIntoViewIfNeeded
- getComputedStyle getBoundingClientRect()
重绘和重排的区别
重绘 当页面中元素样式的改变并不影响它在文档流中的位置时候(color bg visibility)时候,浏览器会把新样式赋予给元素并重新绘制它
当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树
1)添加、删除可见的dom
2)元素的位置改变
3)元素的尺寸改变(外边距、内边距、边框厚度、宽高等几何属性)
4)页面渲染初始化
5)浏览器窗口尺寸改变
性能影响: 重排必然引起重绘,重绘不一定绘重排
有时候即使回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流
如何避免?
浏览器优化
现代的浏览器都是很聪明的,由于每次重排都会造成额外的计算消耗,
因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,
直到过了一段时间或者操作达到了一个阈值(界限),才清空队列。但是!当你获取布局信息的操作的时候,会强制队列刷新,
比如当你访问以下属性或者使用类以下方法时候1
2
3offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回正确的值。
因此,我们在修改样式的时候,最好避免使用上面列出的属性,他们都会刷新渲染队列css
避免使用table布局
尽可能在DOM 树 的最末端改变class
回流可以自上而下,或自下而上的回流的信息传递给周围的节点。回流是不可避免的,但可以减少其影响。
尽可能在DOM树的里面改变class,可以限制了回流的范围,使其影响尽可能少的节点避免设置多层内联样式,改成使用外部类统一修改
通过style属性设置样式,每个dom元素都会造成回流,样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一次回流将动画效果应用到
position
属性为absolute
或者fixed
的元素上
脱离文档流,否则会引起父元素以及后续元素的频繁回流避免使用
css
表达式将元素提升为合成层
- 合成层 的 位图,会交给 GPU 合成,比CPU处理要快
- 当需要repaint时候,只需要 repaint本身,不会影响到其他的层
- 对于transform 和 opacity效果,不会触发重绘和重排
- 提升合成层最好的方式就是使用CSS will-change
javascript
- 避免频繁操作样式,最好一次性重写,或者将样式列表定义为
class
并一次性更改class 属性 - 避免频繁操作DOM,创建一个
documentFragment
,它在上面应用所有DOM操作
,最后再把它添加到文档中
documentFragment - 也可以先为元素设置
display:none
,操作结束后再把它显示出来,因为再display
属性为none
的元素上进行的DOM
操作不会引发回流和重绘 - 避免频繁读取会引发回流和重绘的属性,如果确实需要多次使用,就用一个变量缓存起来
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引发父元素以及后续元素频繁回流
- 避免频繁操作样式,最好一次性重写,或者将样式列表定义为
- 常见的 浏览器内核 有哪些?
- chrome : Blink(28~) Webkit (27) / V8
- FireFox: Geoko/SpiderMonkey
- Safari: Webkit/JavaScriptCore
- Edge: EdgeHtml/Chakra
DOM Tree 是 如何 构建的 ?
- 转码: 浏览器 接收的 二进制 数据按照 指定编码 格式转化 为 HTML 字符串
- 生成 Tokens(词法分析): 之后开始parser,浏览器会将HTML字符串解析成Tokens
- 构建成Nodes,对Node添加特定的属性,通过指针确定Node的父、子、兄弟关系和所属 treeScope
- 生成DOM Tree:通过node 包含的指针确定的关系构建出DOM
跨域问题
- jsonp 同源策略
- jsonp 本质上 是 一个Hack,它利用标签 不受同源 策略限制 的特性进行 跨域操作
- jsonp 优点: 实现简单,兼容性好
- jsonp 缺点:
- 只支持 get请求(因为script标签只能 get)
- 有安全性畏问题,容易遭受 xss攻击
- 需要服务端配合进行jsonp改造
- CORS (跨域资源共享)
CORS是目前主流的跨域解决方案,跨域资源共享(CORS)是一种机制,它使用 额外的 HTTP 头来告诉 浏览器,
让运行在一个 origin(domain)上的Web应用被准许访问来自不同源服务器上指定的资源
当一个资源从该资源本身所在的服务器不同的域,协议或者端口请求一个资源时候,资源会发起一个跨域HTTP请求
- jsonp 同源策略
如果你使用express,可以在后端设置
1 | var allowCrossDomain = function(req,res,next){ |
- nginx: ngix 是一款及其强大的web服务器,其优点是轻量级,启动快,高并发
利用nginx 做反向代理
nginx 反向代理的原理很简单: 所有客户端的请求 都必须经过nginx的处理,nginx 作为反向代理服务器再将请求转发给node或者JAVA 服务,规避了同源问题1
2
3
4
5
6
7
8
9http{
add_header Access-Control-Allow-Origin *
add_header Access-Control-Allow-Origin X-Request-Width
add_header Access-Control-Allow-Origin GET,POST,OPTIONS
# server 模块配置是http模块中的一个子模块,用来定义一个虚拟访问主机
server {
}
}