最近在学习性能优化,学习了雅虎军规 ,但是觉着有点云里雾里的,由于里面有些东西虽然本身也一直在使用,可是感受不太明白因此然,好比减小DNS查询,css和js文件的顺序。因此就花了时间去了解浏览器的工做,有一篇经典的文章《how browsers work》 ,讲的很详细,也有中文译本 。不过就是文章有点太长,也讲了一堆东西,仍是本身总结一下。javascript
好,咱们先说一下,为何要了解这些呢?若是想写出一个最佳实践的页面,就要好好了解。css
正文开始html
浏览器的主要功能是将用户选择的web资源呈现出来,它须要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式一般是HTML,也包括PDF、image及其余格式。用户用URI(Uniform Resource Identifier统一资源标识符)来指定所请求资源的位置,经过DNS查询,将网址转换为IP地址。整个浏览器工做的流程,以前博客中有论述:
一、输入网址。
二、浏览器查找域名的IP地址。
3. 浏览器给web服务器发送一个HTTP请求
4. 网站服务的永久重定向响应
5. 浏览器跟踪重定向地址 如今,浏览器知道了要访问的正确地址,因此它会发送另外一个获取请求。
6. 服务器“处理”请求,服务器接收到获取请求,而后处理并返回一个响应。
7. 服务器发回一个HTML响应
8. 浏览器开始显示HTML
9. 浏览器发送请求,以获取嵌入在HTML中的对象。在浏览器显示HTML时,它会注意到须要获取其余地址内容的标签。这时,浏览器会发送一个获取请求来从新得到这些文件。这些文件就包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取相似的过程。因此浏览器会在DNS中查找这些域名,发送请求,重定向等等…java
那么,一个页面,到底是如何从咱们输入一个网址到最后完整的呈如今咱们面前的呢?还须要了解一下浏览器是如何渲染的:web
下面是渲染引擎在取得内容以后的基本流程:后端
解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树浏览器
先来看个图:性能优化
因此,浏览器会解析三个东西:
(1) HTML/SVG/XHTML,解析这三种文件会产生一个 DOM Tree。
(2) CSS,解析 CSS 会产生 CSS 规则树。
(3) JavaScript脚本,主要是经过 DOM API 和 CSSOM API 来操做 DOM Tree 和 CSS Rule Tree.服务器
我今天又纠结了一上午,究竟是怎么解析怎么渲染的,个人疑问在于,浏览器究竟是先解析生成了DOM树,而后再加载CSS JS文件进行渲染,仍是在生成DOM的过程当中,遇到了 link script 而后就加载CSS JS,边加载边渲染。我有这种疑问的缘由在于,看网上的帖子,说的根本不同好嘛! 好比这篇 我想说,这个写的让我直接懵逼,真的是直接懵逼啊,学习的过程当中,总会遇到困难,但此次,让我真的好难啊。不过正由于不懂才继续查资料继续学习嘛 ==!我又查了一上午,本身测试测试测试,而后觉着,我好像是明白点了。真的推荐你们去认真看《how browsers work》这篇文章,学习不懂得知识的时候,仍是要从比较权威的资料看起比较好,也不要像我今天这样,无头苍蝇乱查。网络
那么就来讲一下图中的过程,我是按照本身的理解来讲,若是有误,欢迎指正。
当浏览器得到一个html文件时,会
“自上而下”
加载,并在加载过程当中进行解析渲染。
解析:
1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的全部子节点都构建好后才会去构建当前节点的下一个兄弟节点。
2. 将CSS解析成 CSS Rule Tree 。
3. 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,由于一些像 Header 或 display:none 的东西就不必放在渲染树中了。
4.有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操做称之为Layout,顾名思义就是计算出每一个节点在屏幕中的位置。
5.再下一步就是绘制,即遍历render树,并使用UI后端层绘制每一个节点。
上述这个过程是逐步完成
的,为了更好的用户体验,渲染引擎将会尽量早的将内容呈现到屏幕上,并不会等到全部的html都解析完成以后再去构建和布局render树。它是解析完一部份内容就显示一部份内容,同时,可能还在经过网络下载其他内容。(这段话是《how browsers work》里面讲的,让我茅塞顿开)
几个概念:
(1)Reflow(回流):浏览器要花时间去渲染,当它发现了某个部分发生了变化影响了布局,那就须要倒回去从新渲染。
(2)Repaint(重绘):若是只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引发浏览器的repaint,重画某一部分。
Reflow要比Repaint更花费时间,也就更影响性能。因此在写代码的时候,要尽可能避免过多的Reflow。
(1)页面初始化的时候;
(2)操做DOM时;
(3)某些元素的尺寸变了;
(4)若是 CSS 的属性发生变化了。
(1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,而后修改 DOM 的 className。
(2)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。
(3)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
(4)千万不要使用 table 布局。由于可能很小的一个小改动会形成整个 table 的从新布局。
我应该是已经把网上全部的关于浏览器加载 解析 渲染过程的文章都看全了,其中写的比较好的一个版本是下面这个:
HTML页面加载和解析流程
1. 用户输入网址(假设是个html页面,而且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
4. 浏览器继续载入html中<body>部分的代码,而且CSS文件已经拿到手了,能够开始渲染页面了;
5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
6. 服务器返回图片文件,因为图片占用了必定面积,影响了后面段落的排布,所以浏览器须要回过头来从新渲染这部分代码;
7. 浏览器发现了一个包含一行Javascript代码的<script>标签,赶快运行它;
8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。忽然少了这么一个元素,浏览器不得不从新渲染这部分代码;
9. 终于等到了</html>的到来,浏览器泪流满面……
10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径;
11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得从新来过……”,浏览器向服务器请求了新的CSS文件,从新渲染页面。
CSS选择符是从右到左进行匹配的。从右到左!因此,#nav li 咱们觉得这是一条很简单的规则,秒秒钟就能匹配到想要的元素,可是,可是,可是,是从右往左匹配啊,因此,会去找全部的li,而后再去肯定它的父元素是否是#nav。,所以,写css的时候须要注意:
如今,咱们大都会将script标签放在body结束标签以前,那缘由是什么呢?我今天也作了一个测试。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>测试js代码位置</title> <script type="text/javascript"> var item = document.getElementById("item"); cosole.log(item); </script> </head> <body> <div id="item" width="100px" height="100px"> 你好 </div> </body> </html>
上述代码中有一段js代码,要在控制台打印一个元素,我把script标签放在head里,控制台里打印出来的是null。 我又把js代码放在body结束标签以前,打印出来的就是div元素了