浏览器的解析和执行过程

当浏览器得到一个html文件时,会“自上而下”加载,并在加载过程当中进行解析渲染。
解析:
1. 浏览器会将HTML解析成一个DOM树(display:none,visibility:hidden)。 DOM 树的构建过程是一个深度遍历过程:当前节点的全部子节点都构建好后才会去构建当前节点的下一个兄弟节点。
2. 将CSS解析成 CSS Rule Tree 。
3. 根据DOM树和CSSOM来构造 Rendering Tree( visibility:hidden )。
4.有了Render Tree, 浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步Layout
5.再下一步就是绘制,即遍历render树,并使用UI后端层绘制每一个节点。
 
过程是这样的:
 

 

 
 
 
这里写图片描述
 
 
上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽量早的将内容呈现到屏幕上,并不会等到全部的html都解析完成以后再去构建和布局render树。它是解析完一部份内容就显示一部份内容,同时,可能还在经过网络下载其他内容。(这段话是《how browsers work》里面讲的,让我茅塞顿开)
 
几个概念:
(1)Reflow(回流):浏览器要花时间去渲染,当它发现了某个部分发生了变化影响了布局,那就须要倒回去从新渲染。
(2)Repaint(重绘):若是只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引发浏览器的repaint,重画某一部分。
Reflow要比Repaint更花费时间,也就更影响性能。因此在写代码的时候,要尽可能避免过多的Reflow。

reflow的缘由
(1)页面初始化的时候;
(2)操做DOM时;
(3)某些元素的尺寸变了;
(4)若是 CSS 的属性发生变化了。
 
减小 reflow/repaint
 
 (1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,而后修改 DOM 的 className。
 (2)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。
 (3)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
 (4)千万不要使用 table 布局。由于可能很小的一个小改动会形成整个 table 的从新布局。
 
编写CSS时应该注意:
 
CSS选择符是从右到左进行匹配的。从右到左!因此,#nav li 咱们觉得这是一条很简单的规则,秒秒钟就能匹配到想要的元素,可是,可是,可是,是从右往左匹配啊,因此,会去找全部的li,而后再去肯定它的父元素是否是#nav。,所以,写css的时候须要注意:
 
关于script标签的位置
 
如今,咱们大都会将script标签放在body结束标签以前,那缘由是什么呢?我今天也作了一个测试。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>测试js代码位置</title>
  6. <script type="text/javascript">
  7. var item = document.getElementById("item");
  8. cosole.log(item);
  9. </script>
  10. </head>
  11. <body>
  12. <div id="item" width="100px" height="100px">
  13. 你好
  14. </div>
  15. </body>
  16. </html>
js 的加载特色:
(1)载入后立刻执行,哪怕浏览器还在渲染html
(2)执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。缘由:由于浏览器须要一个稳定的DOM树结构,而JS中颇有可能有 代码直接改变了DOM树结构,好比使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修 改DOM树,须要从新构建DOM树的状况,因此 就会阻塞其余的下载和呈现。因此,js 死循环执行不完的话,页面也就别想呈现了;
 
 
 
减小 JavaScript 对性能的影响的方法:
 
将全部的script标签放到页面底部,也就是body闭合标签以前,这能确保在脚本执行前页面已经完成了DOM树渲染。
尽量地合并脚本。页面中的script标签越少,加载也就越快,响应也越迅速。不管是外链脚本仍是内嵌脚本都是如此。
采用无阻塞下载 JavaScript 脚本的方法:
(1)使用script标签的 defer 属性;
(2)使用动态建立的script元素来下载并执行代码;
 
因此,总结一下,一个浏览器完整的加载顺序:

1. 用户输入网址(假设是个 HTML 页面,而且是第一次访问),浏览器拿到 HTML 文件准备解析成Dom tree;javascript

2. 浏览器开始载入 HTML 代码,发现 <head> 标签内有一个 <link> 标签引用外部 CSS 文件;css

3. 浏览器又发出 CSS 文件的请求,服务器返回这个 CSS 文件, 准备解析成CSS tree;html

4. 浏览器继续载入 HTML 中 <body> 部分的代码,而且 CSS 文件已经拿到手了,能够layout;java

5. 浏览器在代码中发现一个 <img> 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;后端

6. 服务器返回图片文件,因为图片占用了必定面积,影响了后面段落的排布,所以浏览器须要回过头来从新渲染这部分代码;浏览器

7. 浏览器发现了一个包含一行 JavaScript 代码的 <script> 标签,赶快运行它;服务器

8. JavaScript 脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 <div>(style.display=”none”)。杯具啊,忽然就少了这么一个元素,浏览器不得不从新渲染这部分代码;网络

9. 终于等到了 </html> 的到来,浏览器泪流满面……app

10. 等等,还没完,用户点了一下界面中的“换肤”按钮,JavaScript 让浏览器换了一下 <link> 标签的 CSS 路径;布局

11. 浏览器召集了在座的各位 <div><span><ul><li> 们,“大伙儿收拾收拾行李,咱得从新来过……”,浏览器向服务器请求了新的CSS文件,从新渲染页面。 浏览器天天就这么来来回回跑着,要知道不一样的人写出来的 HTML 和 CSS 代码质量良莠不齐,说不定哪天跑着跑着就挂掉了。好在这个世界还有这么一群人——页面重构工程师,平时挺不起眼,也就帮视觉设计师们切切图啊改改字,其实背地里仍是干了很多实事的。

相关文章
相关标签/搜索