浏览器的加载、解析、和渲染--总结

来源:互联网 发布:vb用户管理系统 编辑:程序博客网 时间:2024/05/24 06:45

浏览器的加载、解析和渲染

浏览器的主要功能是将用户选择的web资源呈现出来,它需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是HTML,也包括PDFimage及其他格式。用户用URIUniform Resource Identifier统一资源标识符)来指定所请求资源的位置,通过DNS查询,将网址转换为ip地址。

一.浏览器的主要组件包括

用户界面:包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分;

v浏览器引擎:用来查询及操作渲染引擎的接口;

v渲染引擎:用来显示请求的内容,例如,如果请求内容为html,它负责解析htmlcss,并将解析后的结果显示出来;

网络:用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作;

 UI后端:用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口;

JS解释器:用来解释执行JS代码;

7.数据存储:H5定义了web database技术,这是一种轻量级完整的客户端存储技术。

:为什么要了解浏览器渲染页面和加载页面机制,主要还是性能的优化。

了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以最快的速度将文件加载完毕。

了解浏览器如何进行解析,我们可以在构建DOM结构,组织css选择器时,选择最优的写法,提高浏览器的解析速率。

了解浏览器如何进行渲染,明白渲染的过程,我们在设置元素属性,编写js文件时,可以减少重绘“”重新布局的消耗。

这三个过程在实际进行的时候又不是完全独立,而是会有交叉。会造成一边加载,一边解析,一边渲染的工作现象。

:用户访问网页都发生了什么。

用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址,找到后,系统会向对应IP地址的网络服务器发送一个http请求。

网络服务器解析请求,并发送请求给数据库服务器。

数据库服务器将请求的资源返回给网络服务器,网络服务器解析数据,并生成html文件,放入http response中,返回给浏览器。

浏览器解析 http response

浏览器解析 http response后,需要下载html文件,以及html文件内包含的外部引用文件,及文件内涉及的图片或者多媒体文件。(这里进入主题了也就是下面的第三大点)

1~4步骤HTTP协议的一些内容,访问服务器端可能遭遇的问题:如果网络服务器无法获取数据库服务器返回的资源文件(http response 404),或者由于并发原因暂时无法处理用户的http请求(http response 500)。

三:浏览器渲染页面和解析加载页面机制。

  加载,即为获取资源文件的过程,不同浏览器,以及他们的不同版本在实现这一过程时,会有不同的实现效果(资源间互相阻塞,可以用timeline来做测试)。这里先说下浏览器的5个常驻线程:

    1.浏览器GUI渲染线程用来显示请求的内容,例如,如果请求内容为html,它负责解析htmlcss,并将解析后的结果显示出来;

    2.javascript引擎线程专门处理JavaScript脚本的虚拟机

      3.浏览器定时器触发线程(setTimeout

      4.浏览器事件触发线程

      5.浏览器http异步请求线程(.jpg、视频、 <link />这类请求)

 备注:现代浏览器存在 prefetch优化,浏览器会另外开启线程,提前下载jscss文件,需要注意的是,预加载js并不会改变dom结构,他将这个工作留给主加载。

加载顺序:

1.浏览器解析http response下载html文件会自上而下加载,并在加载过程中进行解析渲染。自上而下加载时遇到图片、视频之类资源时便会进入第5个线程,这是异步请求,并不会影响html文档进行加载。

2.加载过程中遇到外部css文件,浏览器另外发出一个请求,来获取css文件。这里也是第5个线程,这里css解析会生成一个rule tree(规则树),这个以后会更新。

3.当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。

原因JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。
办法:可以将外部引用的js文件放在</body>前。

4. css可能影响js的执行造成阻塞。

原因:js里面var width = $('#id').width();这里js执行前,浏览器必须保证之前的css文件已下载和解析完成(后面的不会影响),这也是css阻塞后续js的根本原因。当js文件不需要依赖css文件时,可以将js文件放在头部css的前面。

Html文档解析完毕之后,在这个阶段,浏览器将文档标记为可交互的,并开始解析处于延时模式中的脚本——这些脚本在文档解析后执行。

上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

文档状态将被设置为完成,同时触发一个load事件。

总结一下页面加载和解析的流程:

① 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;

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

③ 浏览器又发出CSS文件的请求,服务器返回这个CSS文件; 

④ 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;

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

⑥ 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码; 

⑦ 浏览器发现了一个包含一行javascript代码的<script>标签,赶快运行它; 

⑧ Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=none”)。突然少了这么一个元素,浏览器不得不重新渲染这部分代码;

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

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

⑪  浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。

四.重绘和重排

① Reflow重排):浏览器要花时间去渲染,当它发现了某个部分发生了变化影响了布局,那就需要倒回去重新渲染。 

② Repaint(重绘):如果只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的repaint,重画某一部分。 
Reflow要比Repaint更花费时间,也就更影响性能。所以在写代码的时候,要尽量避免过多的Reflow

reflow的原因:

① 页面初始化的时候;

② 操作DOM时; 

③ 某些元素的尺寸变了; 

④ 如果 CSS的属性发生变化了。

减少重绘和重排:

① 将多次改变样式属性的操作合并成一次操作;

②  将需要多次重排的元素,position属性设为absolutefixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位

③ 在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的html片段,再一次性添加到文档中去,而不是循环添加每一行。

④ 由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排。

⑤ 在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量(不是很理解);

⑥ 不要使用 table布局。因为可能很小的一个小改动会造成整个 table的重新布局。

五.其他一些问题

javascript 位置

① 如果在解析html的时候遇到js会阻塞页面渲染,所以一般我们会将所有的script标签放到页面底部,也就是body闭合标签之前,这能确保在脚本执行前页面已经完成了DOM树渲染。尽可能地合并脚本。页面中的script标签越少,加载也就越快,响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。

② 采用无阻塞下载 JavaScript脚本的方法: 
           使用script标签的deferasync属性、; 
           使用动态创建的script元素来下载并执行代码等异步加载等方法;

deferasync区别:

deferasync都是异步下载,但是执行时刻不一致;

相同点:

加载文件时不阻塞页面渲染;

使用这两个属性的脚本中不能调用document.write方法;

允许不定义属性值,仅仅使用属性名;

不同点:

html的版本html4.0中定义了deferhtml5.0中定义了async;这将造成由于浏览器版本的不同而对其支持的程度不同;

每一个async属性的脚本都在它下载结束之后立刻执行,同时会在windowload事件之前执行,所以就有可能出现脚本执行顺序被打乱 的情况;

每一个defer属性的脚本都是在页面解析完毕之后,按照原本的顺序执行,同时会在documentDOMContentLoaded之前执行;

css注意事项

css选择符是从右到左进行匹配的。所以,#nav li我们以为这是一条很简单的规则,秒秒钟就能匹配到想要的元素,所以,会去找所有的li,然后再去确定它的父元素是不是#nav。因此,写css的时候需要注意:

dom深度尽量浅。

减少inline javascriptcss的数量。

使用现代合法的css属性。

不要为id选择器指定类名或是标签,因为id可以唯一确定一个元素。

避免后代选择符,尽量使用子选择符。原因:子元素匹配符的概率要大于后代元素匹配符。后代选择符;#tp p{}子选择符:#tp>p{}

避免使用通配符,举一个例子,.mod .hd *{font-size:14px;}根据匹配顺序,将首先匹配通配符,也就是说先匹配出通配符,然后匹配.hd(就是要对dom树上的所有节点进行遍历他的父级元素),然后匹配.mod,这样的性能耗费可想而知.

六.如何加快HTML页面加载速度

页面减肥
页面的肥瘦是影响加载速度最重要的因素删除不必要的空格、注释inlinescriptcss移到部文件可以使用HTML Tidy来给HTML减肥,还可以使用一些压缩工具来给JavaScript减肥

减少文件数量
减少页面上引用的文件数量可以减少HTTP连接数
许多javascriptCSS文件可以合并最好合并

减少域名查询
DNS查询和解析域名也是消耗时间的,所以要减少对外部JavaScriptCSS、图片等资源的引用,不同域名的使用越少越好

缓存重用数据
使用缓存

优化页面素加载顺序
首先加载页面最初显示的内容和与之相关的JavaScriptCSS然后加载DHTML相关的东西像什么不是最初显示相关的图片、flash、视频等很肥的资源就最后加载

减少inline JavaScript的数量
浏览器parser会假设inline JavaScript会改变页面结构,所以使用inline JavaScript开销较大(比如我们在一个HTML对象生成过程中,使用了inline方式定义的函数,那么这个元素生成几次,那个函数也就要同时生成几次。)不要使用document.write()这种输出内容的方法,使用现代W3C DOM方法来为现代浏览器处理页面内容

指定图像和tables的大小
如果浏览器可以立即决定图像或tables的大小,那么它就可以马上显示页面而不要重新做一些布局安排的工作这不仅加快了页面的显示,也预防了页面完成加载后布局的一些不当的改变image使用heightwidth
table使用table-layout: fixed并使用colcolgroup标签指定columnswidth

自己总结:1.当浏览器获得一个html文件时,会自上而下加载,并在加载过程中进行解析渲染。

当资源加载中遇到js脚本的时候,因为脚本可能改变文档流,甚至跳转页面,所以在不使用deferasync属性的情况下会暂停该脚本之下所有资源的下载,直到脚本下载执行结束之后,如果脚本是外引的,则网络必须先请求到这个资源——这个过程也是同步的,会阻塞文档的解析直到资源被请求到并加载执行完毕。当资源加载遇到样式表的时候,因为样式表不会改变DOM树,所以不会阻塞之后的文档的加载解析,但是脚本可能在文档的解析过程中请求样式信息,如果样式还没有加载和解析,脚本将得到错误的值,显然这将会导致很多问题,所以样式表可能会阻塞之后的脚本,不同的浏览器的处理不同,Firefox在存在样式表还在加载和解析时阻塞所有的脚本,而Chrome只在当脚本试图访问某些可能被未加载的样式表所影响的特定的样式属性时才阻塞这些脚本。

 2.浏览器会将HTML解析成一个DOM树,DOM树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。 

3.渲染引擎的职责就是渲染,即在浏览器窗口中显示所请求的内容下面是渲染引擎在取得内容之后的基本流程:

解析html以构建dom,解析css以构建规则树 ->构建render-> 布局render-> 绘制render

具体过程为:

① HTML构建成一个DOM树(DOM = Document Object Model 文档对象模型),DOM树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。 

② CSS解析成CSS规则树去构造CSSOM( CSSOM = CSS Object Model CSS对象模型)

③ 根据DOM树和CSSOM来构造Rendering Tree(渲染树)。注意:Rendering Tree渲染树并不等同于 DOM树,因为一些像 Headerdisplay:none的东西就没必要放在渲染树中了。有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。

④ 下一步操作称之为Layout,顾名思义就是计算出每个节点在屏幕中的位置layout render tree 

⑤ 再下一步就是绘制,即遍历render树,并使并使用浏览器UI后端层绘制每个节点。

 

      4.Dom树构建完成时,浏览器开始构建另一棵树——渲染树。

      5. css下载后会马上渲染到页面,渲染和下载同步进行

原创粉丝点击