葡京网投哪个正规 > 新葡亰-前端 > 浏览器加载解析渲染网页原理,渲染机制

原标题:浏览器加载解析渲染网页原理,渲染机制

浏览次数:151 时间:2019-11-30

占位图

当使用样式表中的背景图片作为占位符时,要把背景图片转为base64格式。这是因为背景图片加载的顺序在标签后面,背景图片可能会在<img>标签图片加载完成后才开始加载,达不到想要的效果。

 

即时运行错误的捕获方式

// 代码块使用错误捕获
try {} catch (e) {}

// 使用window对象错误事件捕获
window.onerror = function(e) {}
window.addEventListener('error', function(e) {})

葡京正网网投 1

预加载

很多场景里图片是在改变或触发状态后才显示出来的,例如点击一个Tab后,一个设置display:none隐藏的父元素变为显示,这个父元素里的子元素图片会在父元素显示后才开始加载;又如当鼠标hover到图标后,改变图标图片,图片会在hover上去后才开始加载,导致出现闪一下这种不友好的体验。

在这种场景下,我们就需要把图片预加载,预加载有很多种方式:

  1. 若是小图标,可以合并成雪碧图,在改变状态前就把所有图标都一起加载了。
  2. 使用上文讲到的,设置了display:none属性的元素,图片不会渲染出来,但会加载。把要预加载的图片加到设置了display:none的元素背景图或``标签里。
  3. 在javascript创建img对象,把图片url设置到img对象的src属性里。

    1 赞 3 收藏 评论

葡京正网网投 2

以上内容摘自

渲染机制

1.创建document对象,开始解析web页面。解析HTML原始和他们的文件内容添加Element对象和Text节点到文档中。阶段:document.readyState = "loading"。(表示可以触发一次document.onreadystatechange事件)

伪类的背景图片

.img-green { background-image: url(../image/green.png); } .img-green:hover{ background-image: url(../image/red.png); }

1
2
3
4
5
6
.img-green {
    background-image: url(../image/green.png);
}
.img-green:hover{
    background-image: url(../image/red.png);
}

触发hover前的图片资源请求如下:
葡京正网网投 3

触发hover后的图片资源请求如下:
葡京正网网投 4

当触发伪类的时候,伪类样式上的背景图片才会加载。

原理

触发hover前,DOM树与样式规则树匹配的是无hover状态选择器.img-green的样式,因此渲染树上background-image属性的值是url(../image/green.png),解析渲染树时加载的是green.png,绘制时渲染的也是green.png

触发hover后,因为.img-green:hover的优先级比较高,因此DOM树与样式规则树匹配的是有hover状态选择器.img-green:hover的样式,渲染树上background-image属性的值是url(../image/red.png),解析渲染树时加载的是red.png,绘制时渲染的也是red.png

● 宽带网速
● DNS服务器的响应速度
● 服务器的处理能力
● 数据库性能
● 路由转发
● 浏览器处理能力

声明文档类型

  • HTML5 <!DOCTYPE html>
  • HTML 4.01 有宽松模式和严格模式(不包括展示性和弃用的元素)

<img src="" alt="Baidu" align="bottom" border="0">

浏览器的工作流程

要研究图片资源的加载和渲染,我们先要了解浏览器的工作原理。以Webkit引擎的工作流程为例:

葡京正网网投 5

从上图可看出,浏览器加载一个HTML页面后进行如下操作:

  • 解析HTML —> 构建DOM树
  • 加载样式 —> 解析样式 —> 构建样式规则树
  • 加载javascript —> 执行javascript代码
  • 把DOM树和样式规则树匹配构建渲染树
  • 计算元素位置进行布局
  • 绘制

从上图我们不能很直观的看出图片资源从什么时候开始加载,下图标出图片加载和渲染的时机:

  • 解析HTML【遇到<img>标签加载图片】 —> 构建DOM树
  • 加载样式 —> 解析样式【遇到背景图片链接不加载】 —> 构建样式规则树
  • 加载javascript —> 执行javascript代码
  • 把DOM树和样式规则树匹配构建渲染树【加载渲染树上的背景图片】
  • 计算元素位置进行布局
  • 绘制【开始渲染图片】

网页性能影响:
  网页生成的时候,至少会渲染一次。用户访问的过程中,还会不断重新渲染。重新渲染,就需要重新生成布局和重新绘制。前者叫做"重排"(reflow),后者叫做"重绘"(repaint)。提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染。

非核心代码异步加载

  • 动态脚本加载
    动态创建<script>标签添加到html 文档中内
  • <script> 标签的defer 属性
    html 文档解析完执行,按加载顺序依次执行
  • <script> 标签的async 属性
    html 文档解析完执行,加载顺序与执行顺序无关

var n =Number(new Date;

Web图片资源的加载与渲染时机

2017/07/27 · JavaScript · 渲染

原文出处: Leechikit   

此文研究页面中的图片资源的加载和渲染时机,使得我们能更好的管理图片资源,避免不必要的流量和提高用户体验。

网页生成的过程:

前端错误监控

  • 保证产品质量
  • 即时运行错误(代码错误)收集
  • 资源加载错误收集

3.3通用的资源加载器——ResourceLoader类,是在WebKit需要从网络或者文件系统获取资源的时候使用该类只负责获得资源的数据,因此被所有特定资源加载器所共享,它属于CachedResource类,与CachedResourceLoader类没有继承关系。

应用

  async 脚本在它们完成下载完成后的第一时间执行,它处在 window 的load 事件之前。 这意味着有可能(并且很有可能)设置了 async 的脚本不会按照它们在 HTML 中出现的顺序执行。这也意味着他们可能会中断 DOM 的构建。无论它们在何处被指定,设置async 的脚本的加载有着较低的优先级,同步的脚本总是比异步的脚本拥有更高的优先级。他们通常在所有其他脚本加载之后才加载,而不阻塞 DOM 构建。然而,如果一个指定async 的脚本很快就完成了下载,那么它的执行会阻塞 DOM 构建以及所有在之后才完成下载的同步脚。

上报错误的基本原理

  • 采用Ajax 通信方式上报

  • 利用Image 对象上报

<script>
  new Image().src = 'url?k=val'  // 会发送一个请求用于上报
</script>

参考

<link rel="stylesheet" type="text/css" href=".../css/xxx.css">

图片加载与渲染规则

页面中不是所有的<img>标签图片和样式表背景图片都会加载。

 

触发Reflow 条件

  • 增加、删除、修改DOM节点时,会触发Reflow 或 Repaint
  • 移动DOM节点、动画
  • 修改CSS样式
  • resize 窗口、滚动页面
  • 修改页面默认字体

葡京正网网投 6

不存在元素的背景图片

.img-blue { background-image: url(../image/blue.png); } .img-orange{ background-image: url(../image/orange.png); }

1
2
3
4
5
6
.img-blue {
    background-image: url(../image/blue.png);
}
.img-orange{
    background-image: url(../image/orange.png);
}

图片资源请求如下:葡京正网网投 7

不存在元素的背景图片不会加载。

原理

不存在的元素不会产出到DOM树上,因此渲染树上也不会有不存在的元素,当解析渲染树时无法解析不存在的元素,不存在的元素上的图片自然不会加载也不会渲染。

葡京正网网投 8

减少Reflow Repaint的开销

  • DOM拼接后一次append 到页面上(<li>列表</li>)

complete - 载入完成--loaded

display:none

JavaScript

<style> .img-purple { background-image: url(../image/purple.png); } </style> <img src="../image/pink.png" style="display:none"> <div class="img-purple" style="display:none"></div>

1
2
3
4
5
6
7
<style>
.img-purple {
    background-image: url(../image/purple.png);
}
</style>
<img src="../image/pink.png" style="display:none">
<div class="img-purple" style="display:none"></div>

图片资源请求如下:葡京正网网投 9

设置了display:none属性的元素,图片不会渲染出来,但会加载。

原理

把DOM树和样式规则树匹配构建渲染树时,会把可渲染元素上的所有属性(如display:none属性和background-image属性)结合一起产出到渲染树。

当解析渲染树时会加载<img>标签元素上的图片,发现元素上有background-image属性时会加载背景图片。

当绘制时发现元素上有display:none属性,则不计算该元素位置,也不会绘制该元素。

JavaScript

<style> .img-yellow { background-image: url(../image/yellow.png); } </style> <div style="display:none"> <img src="../image/red.png"> <div class="img-yellow"></div> </div>

1
2
3
4
5
6
7
8
9
<style>
.img-yellow {
    background-image: url(../image/yellow.png);
}
</style>
<div style="display:none">
    <img src="../image/red.png">
    <div class="img-yellow"></div>
</div>

图片资源请求如下:
葡京正网网投 10

设置了display:none属性元素的子元素,样式表中的背景图片不会渲染出来,也不会加载;而<img>``标签的图片不会渲染出来,但会加载。

原理

正如上面所说的,构建渲染树时,只会把可渲染元素产出到渲染树,这就意味有不可渲染元素,当匹配DOM树和样式规则树时,若发现一个元素的属性上有display:none,浏览器会认为该元素的子元素是不可渲染的,因此不会把该元素的子元素产出到渲染树上。

当解析渲染树时渲染树上没有设置了display:none属性元素的子元素,因此不会加载该元素中子元素的背景图片。

当绘制时也因为渲染树上没有设置了display:none属性元素的子元素,因此该元素中子元素的背景图片不会渲染出来。

感谢大神们的实践总结~

资源加载错误

<img>等资源加载错误不会冒泡,window.onerror 无法捕获到标签资源加载的错误

  • dom 捕获
elScript.onerror = function (e){}
elImg.onerror = function (e){}
...
  • 跨域js 错误捕获

js 文件资源响应头设置Access-Control-Allow-Origin: *

script 标签增加crossorigin 属性
<script crossorigin src='url'></script>

  • 获取成功加载的资源
performance.getEntries()
performance.getEntries().map(item => item.name) // 获取所有成功资源加载地址
  • 通过Error 事件捕获
window.addEventListener('error', function(e) {
  console.log('捕获', e) // 将会捕获到资源加载错误
}, true)
<script src='错误url'></script>

重排/回流

重复图片

JavaScript

.img-blue { background-image: url(../image/blue.png); } <div class="img-blue"></div> <img src="../image/blue.png"> <img src="../image/blue.png">

1
2
3
4
5
6
.img-blue {
    background-image: url(../image/blue.png);
}
<div class="img-blue"></div>
<img src="../image/blue.png">
<img src="../image/blue.png">

图片资源请求如下:
葡京正网网投 11

页面中多个<img>标签或样式表中的背景图片图片路径是同一个,图片只加载一次。

原理

浏览器请求资源时,都会先判断是否有缓存,若有缓存且未过期则会从缓存中读取,不会再次请求。先加载的图片会存储到浏览器缓存中,后面再次请求同路径图片时会直接读取缓存中的图片。

  网站的性能优化,从用户输入网址,到用户最终看到结果,需要有很多的参与方共同努力。这些参与方中任何一个环节的性能都会影响到用户体验。

DNS 预解析

// 强制打开a 标签的DNS 预解析,https 默认关闭a 标签的DNS 预解析
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="dns-prefatch" href="url">

葡京正网网投 12

1.HTML 描述了一个页面的结构。浏览器首先会将HTML转换成其能够理解的一种格式 – 文档对象模型(Document Object Model) 或者简称为 DOM,每一个 HTML 标签都对应着树种的某个节点(DOM节点)。

DOCTYPE

  • DOCTYPE是用来声明文档类型的,告诉浏览器使用哪一种DTD规范的文档类型。
  • DTD(document type definition, 文档类型定义) 是一些列的语法规则,用来定义HTML文件类型。用来给浏览器判断文档类型。

</div>

  新的 Web 标准 <link rel="preload" href="" as="" >使能够更快地加载关键资源,as属性告诉浏览器要下载的是什么,一些可能的值是:script,style,image,font,audio,video.有一点要注意,要预加载字体你还必须设置crossorigin 属性,即使字体在同一个域名下。

提升页面性能的方法有哪些?

  • 资源压缩合并,减少HTTP请求
  • 非核心代码异步加载
  • 利用浏览器缓存
  • 使用CDN
  • 预解析DNS

}

● 解析HTML【遇到标签加载图片】 —> 构建DOM树
● 加载样式 —> 解析样式【遇到背景图片链接不加载】 —> 构建样式规则树
● 加载javascript —> 执行javascript代码
● 把DOM树和样式规则树匹配构建渲染树【加载渲染树上的背景图片】
● 计算元素位置进行布局
● 绘制【开始渲染图片】

浏览器渲染过程

葡京正网网投 13

  • HTML通过HTML解析转化成DOM树

    葡京正网网投 14

  • Style样式通过CSS解析转化成Style规则

    葡京正网网投 15

    image.png

  • DOM树和Style规则结合成渲染树(Render Tree)

    葡京正网网投 16

  • 然后渲染树通过layout 计算出各元素在浏览器上的宽高颜色位置等属性,最后在浏览器上进行绘制。

    葡京正网网投 17

了解了DOMTree和CSSTree的构建原理,然后合成randerTree绘制页面,但是这个过程怎么能缺少JS呢?有了JS的参与,这个过程就会变得复杂了。首先,CSS资源是异步加载,在CSS资源加载的过程中,DOM解析会继续执行操作。但是当遇到script标签的时候,如果是外部资源就要立即加载,如果是内部资源就会立即执行JS代码,立即执行JS代码会阻断HTML的解析(因为JS会操作DOM节点增删改查什么的,还会操作元素样式),霸道总裁JS就这样让傻媳妇HTML傻呆着让它为所欲为了。就算是外部JS资源加载的过程HTML的解析也是被阻断的,这个过程是必须等到JS加载完,然后还要等他执行完才能继续解析HTML。

3.结合DOM和CSSOM,生成一颗渲染树

打开浏览器,在地址栏输入 url 直到页面展现,整个过程发生了什么?

  • DNS(Domain Name System)域名系统预解析(应用层),输入url后,浏览器会进行DNS解析出, 对应服务器的ip地址.
  • 浏览器会将用户输入的请求信息打包发送给nginx服务器.
  • 服务器会分析用户的请求寻找处理请求的对应文件,发送给浏览器.
  • 最后浏览器接收服务器的响应,解析并渲染呈现给用户。

interactive - 已加载,文档与用户可以开始交互

  defer 和async这两个属性都告诉浏览器,它可以 “在后台” 加载脚本的同时继续解析 HTML,并在脚本加载完之后再执行。这样,脚本下载就不会阻塞 DOM 构建和页面渲染了。结果就是,用户可以在所有的脚本加载完成之前就能看到页面。

重绘Repaint

  • 当DOM元素盒模型的各种属性确定计算结果后,浏览器根据这些元素的样式属性绘制一遍出现在页面上的过程就是repaint

8.document对象触发DOMContentLoaded事件,这也标志着程序执行从同步执行阶段,转化为事件取动阶段。

 

页面性能优化

9:避免不必要的复杂的 CSS 选择器,尤其是后代选择器(descendant selectors),因为为了匹配选择器将耗费更多的 CPU。

---------------------------分------------割------------------------------------- 

触发Repaint

  • DOM改动
  • CSS改动

葡京正网网投 18

5.将布局绘制在屏幕上

利用浏览器缓存

  • 强缓存:
    客户端无需再次请求服务端,客户端直接根据缓存条件决定是否使用缓存资源
响应header 描述 常用响应返回内容 推荐 特点 缺点 场景
Cache-Control 在多少秒内进行缓存 public, max-age=秒 固定时间 客户端服务端时间可能不一致
Expires 在此时间前进行缓存 格林威治时间 绝对时间 客户端服务端时间可能不一致 兼容http1.0
  • 协商缓存:
    客户端需请求服务端进行比较缓存条件,符合条件则返回304使用缓存资源
响应header 请求header 描述 常用响应返回内容 推荐 特点 缺点 场景
ETag If-None-Match 固定字符串 md5 hash值 检测文件完整性
Last-Modified If-Modified-Since 在某时间后没再更改 格林威治时间 浏览器根据返回的时间自己决定缓存 浏览器差异

关于重排/回流重绘简单来说就是会将已经计算好的布局和构建好的渲染树(randerTree)重新计算和构建全部或者部分。这部分发生在DOMTree和CSSTree解析完成以后,也就是会发生在构建randerTree时和之后,这里我们重点关注发生在randerTree构建时的重排/回流和重绘问题,也是网页渲染除了JS、CSS阻塞之后的性能优化区间。

  设置了display:none属性元素的子元素,样式表中的背景图片不会渲染出来,也不会加载;而标签的图片不会渲染出来,但会加载。
原理:构建渲染树时,只会把可渲染元素产出到渲染树,这就意味有不可渲染元素,当匹配DOM树和样式规则树时,若发现一个元素的属性上有display:none,浏览器会认为该元素的子元素是不可渲染的,因此不会把该元素的子元素产出到渲染树上。

重排Reflow

  • DOM元素的盒模型需要浏览器根据样式计算结果将他们绘制在页面上,这个过程就是reflow

可以看到饿了吗官网的缓存机制是将document主文件和js文件做了缓存处理。这样的处理方式可以很大程度上提高页面性能和降低服务器请求压力,至于为什么就是接下来的内容了。

阮一峰的网络日志

</html>

预解析:

接着我们再来刷新页面看看取了哪些缓存数据:

  defer 比 async 要先引入浏览器。它的执行在解析完全完成之后才开始,它处在DOMContentLoaded事件之前。 它保证脚本会按照它在 HTML 中出现的顺序执行,并且不会阻塞解析。

在构建randerTree时并不会把CSS样式表或者行内样式表示元素大小和位置的数据添加到RanderObject上,而是要基于样式设置:width、height、font-size、display、left、top、bottun、right还有borde、padding、margin的大小,结合上下文的相互作用(比如有子元素自适应父级元素大小和位置或者父元素基于子元素定义自身大小和位置),最后使用RanderObject上的layout()方法计算出确定的元素大小和位置,这个过程layout()方法是递归完成整个计算操作。

 

</script>

4.生成布局

2.遇到link外部css,创建线程加载,并继续解析文档。

2.页面上的 CSS 样式被映射到 CSSOM 上 – CSS 对象模型(CSS Object Model)。CSS 不阻塞 DOM 的构建,它会阻塞 DOM 的渲染,直到 DOM 和 CSSOM 准备好之前,浏览器什么都不会显示

<script type="text/javascript">

图片加载时间和渲染时机:

我们来看Chrome控制台的时间线:

  这五步里面,第一步到第三步都非常快,耗时的是第四步和第五步。
"生成布局"(flow)和"绘制"(paint)这两步,合称为"渲染"(render)。当浏览器构建 DOM 的时候,如果在 HTML 中遇到了一个 <script>...</script>标签,它必须立即执行。如果脚本是来自于外部的,那么它必须首先下载脚本。只有在 JavaScript 引擎执行完代码之后它才会重新开始解析HTML。

当randerTree构建完成以后就会开始绘制页面了,在绘制页面过程中仍然可能发生重排与重绘,但这里需要重点关注的是图层合并,绘制主要是基于CPU的计算来实现,同时浏览器基本上都采用GPU加速的混合模式,其实浏览器本身不需要操作图层合并,因为绘图不管是CPU还是GPU来实现都是基于元素的大小和位置将它们实现的图层,图们本身就在同一个位置,所以无需合并操作。

  设置了display:none属性的元素,图片不会渲染出来,但会加载。
原理:当DOM树和样式规则树匹配构建渲染树时,会把可渲染元素上的所有属性(如display:none属性和background-image属性)结合一起产出到渲染树。当解析渲染树时会加载标签元素上的图片,发现元素上有background-image属性时会加载背景图片。当绘制时发现元素上有display:none属性,则不计算该元素位置,也不会绘制该元素。

一、浏览器加载网页资源的原理

4.遇到script外部JS,并且设置async、defer,浏览器创建线程加载,并继续解析文档。

10.从此,以异步响应方式处理用户输入、网络事件等。//readyState属性返回当前文档的状态

在浏览器内核有一个管理资源的对象CachedResource类,在CachedResource类下有很多子类来分工不同的资源管理,这些资源管理子类分别是:

</body>

由上面的示例可以说明js执行会阻塞DOMTree构建,不然在JS等待的10秒里足够解析一个img元素,但是10秒后只能查询到img1,img2查询不到(打印空DOM节点对象)。当第二次打印的时候两个img节点就都获取到了。接着我们来看看外部JS加载会不会阻塞DOMTree构建:<script>

解释CSS样式表生成CSSTree

</script>

<!-- 设置网速30kb/s测试js是否阻塞渲染 -->

</html>

最后经过这样艰难的过程过后,网页终于呈现在我们桌面,但是注意window事件交互不会等待绘制完成,决定window事件交互的是资源是否全部加载完成,这里指的资源是HTML文档包含内容资源,并不包含外部脚本加载的资源。

同CachedResourceLoader对象一样,资源池也属于HTML文档对象,所以资源池不能无限大,对于资源容量不能无限大的问题浏览器的解决方法有两种:第一种是采用LRU(Least Recent Rsed最近最少使用原则)算法。第二种方法是通过HTTP协议决定是否缓存,缓存多久,以及什么时候更新缓存,然后我们开发时还可决定资源如何拆分,拆分可以让我决定哪些资源缓存,哪些资源不缓存。

</script>

这个资源加载看起来很复杂,但是模块分工很明确,基于资源对象与内存资源缓存的对应关系(每个缓存资源在资源对象上有一个实例),当浏览器触发资源请求时先通过判断资源是否有缓存资源,如果有的话就就直接拿缓存资源给渲染引擎,如果没有就通过网络请求获取资源给渲染引擎,并且同时会将资源缓存到内存中。

var n = Number(new Date;

葡京网投哪个正规,CPU主要负责randerTree的绘制工作,它与GPU的配合在不同浏览器内核中会略微不同,但是在同一个位置出现的图层越多,肯定是对性能的损耗就越大。而且由于CPU主要负责randerTree的绘制,多图层就会对GPU带来很大的工作负载,具体包括:CSS3 3D变形、CSS3 3D 变换、WebGL 和 视频。也有浮动,定位,溢出隐藏,z坐标重叠等都是在绘制过程中比较损耗性能的行为。

下面通过Chrome浏览器来请求饿了吗官网,在控制台查看数据请求的资源加载过程,并且通过刷新页面查看当页面刷新时浏览器在缓存中取了哪些信息:

<li><img src=".../image/xxx.png" alt=""></li>

有了前面对布局的介绍,重排/回流就一目了然了,当由于脚本执行或者浏览器窗口变化,引发RanderObject上的layout()方法重新计算机布局数据,就叫做重排/回流。从字面上的含义来理解重排很容易,就是由于元素的大小和位置变化页面重新排列布局。回流就存在一些逻辑上的理解了,在布局中因为元素节点的位置和大小是存在上下级和同级之间相互影响的,所以如果有脚本修改DOM节点或者大小位置样式,就会对相关连的元素进行判断查找修改的范围指定修改逻辑,制定layout()方法的递归顺序的最优方案,这个查询判断和修改过程就是需要在节点之间来回操作,这也就是回流。实质上重排/回流说的都是一回事。

</script>

5:不要用tables布局的另一个原因就是tables中某个元素一旦触发reflow就会导致table里所有的其它元素reflow。在适合用table的场合,可以设置table-layout为auto或fixed,

<title></title>

<meta charset="UTF-8">

注:这里所说的缓存是内存,不是磁盘。

<li><img src=".../image/xxx.png" alt=""></li>

</script>

所以当构建randerTree的时候由document.onreadystatechange事件、defer的脚本、DOMContentLoaded事件还有不确定的src异步加载的JS脚本都可能在这时候修改元素的大小和位置,甚至修改DOM结构。

葡京正网网投 19

3.1针对每种资源类型的特定加载器,用来加载某一类资源。例如“image”这个元素,该元素需要图片资源,对应的顶资源加载器是ImageLoader类。

解析HTML生成DOMTree

实质上的操作是在资源对象中找到对应资源的物理地址,然后返回给渲染引擎,渲染引擎在渲染页面时根据url获取物理内存中的资源数据。由于资源的唯一特性是url,所以当两个资源有不同的url,但是他们的内容完全相同时,也不会被认定是同一个资源。

6:这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。

下面是一个缩减版的资源请求原理图:

uninitialized - 还未开始载入

6.当文档解析完成后。document.readyState = "interactive"。(表示可以触发一次document.onreadystatechange事件)

五、重排/回流与重绘

<link type="text/css" rel="stylesheet" href="" />

var n3 = Number(new Date;

重排/回流与重绘是会发生在randerTree构造时,也会发生在randerTree构造结束后,都是相对损耗CPU甚至GPU的操作,只是页面首次渲染更值得的我们关注。

<script>

本地获取到了HTML资源后第一步就是解析HTML,也就是常说的DOM解析,首先是创建一个document对象,然后通过DOM解析出每个节点。通过DOM解析发现页面中有css外部样式表需要加载,就立即通过CSS加载器执行加载。解析到img元素发现需要加载图片,就立即通过图片加载器执行加载,这个过程不会等待前面加载的资源加载完成才启动第二个加载,而是通过异步的方法开启多个加载线程,并且浏览器底层会开启多个进程来处理这些线程(Chrome会开启五个进程)。同样解析到了script元素时发现需要外部js资源会立即加载js文件资源。

由Chrome控制台的时间线可以看到外部JS和外部CSS几乎是同时开始加载,CSS加载并没有阻塞JS的加载。既然这样我们再来测试以下CSS加载阻塞JS执行是否是真的?<script>

randerTree生成完以后开始绘制页面

四、JS时间线

<body>

在阐述JS时间线之前,我另外总结了一部分非常重要的内容:JS的异步加载(JS异步加载的三种方案),JS异步加载与下面的内容相关联的内容比较多,建议在了解下面内容之前先了解一下JS异步加载。

while < {

11:请求如下值offsetTop, offsetLeft, offsetWidth, offsetHeight,scrollTop/Left/Width/Height,clientTop/Left/Width/Height,浏览器会发生reflow,建议将他们合并到一起操作,可以减少回流的次数。

10: 尽量不要过多的频繁的去增加,修改,删除元素,因为这可能会频繁的导致页面reflow,可以先把该dom节点抽离到内存中进行复杂的操作然后再display到页面上。

9.当所有async的脚本加载完成,img等加载完成后,document.readyState = "complete",window对象触发事件。(表示可以触发一次document.onreadystatechange事件或者标准浏览器可以触发window.onload事件了)

2、资源缓存

深度优先原则解析构建DOM树和CSS树:

console.log(document.querySelectorAll;//NodeList [img.img1]

3.遇到script外部JS,并没有设置async、defer,浏览器加载,并阻塞,等待JS加载完成并执行脚本,完后继续解析文档。

<script>

<meta charset="utf-8">

<head>

var n2 = Number(new Date;

console.log;//30~40秒 ---- 注释外部js加载代码测试时间差为0秒

葡京正网网投 20

console.log(document.querySelectorAll;//NodeList [img.img1]

</head>

前面介绍了浏览器资源请求与资源加载的基本原理,看上去好像是一个简单的线性步骤,但是实质上浏览器内部是多进程异步加载这些资源的,我们知道网页的效果是基于DOM结构和CSS样式表来完成基本的页面效果呈现,但是JS代码又可以对DOM节点进行增删该查操作,还可以修改DOM的CSS样式,那必然就是需要先有DOM结构,然后添加CSS样式,再就这两个资源的基础通过JS修改后才能呈现出来,但是什么时候加载(指的是下载资源,并不是前面的资源加载到页面上的整个过程)?什么时候执行?什么时候渲染页面?按照什么规则来完成这些工作呢。

页面加载的五个步骤和JS时间线的十个环节:

葡京正网网投 21

<ul>

<script src="" type="text/javascript" charset="utf-8" async defer></script>

可能有人会疑惑我为什么不测试外部CSS会不会阻塞HTML解析,你想想如果CSS阻塞HTML解析那JS加载必须会被阻塞吧,所以CSS加载也就不会阻塞HTML解析了。但是,CSS会阻塞JS执行,也就间接的阻塞了JS后面的DOM解析。

五个步骤:

3.2资源缓存机制的资源加载器,特点是所有特定加载器都共享它来查找并插入缓存资源——CachedResourceLoader类。特定加载器是通过缓存机制的资源加载器来查找是否有缓存资源,它属于HTML的文档对象。

7.文档解析完成后,所有设置有defer的脚本会按照顺序执行。(禁止使用document.wrlte。

深度优先原则就是对每一个结构顺着第一个内部节点一直往内部解析,直到结构尽头,然后再回退到上一个节点,再对第二个节点执行深入优先原则的解析构建。下图是上面示例请求到的HTML资源的解析流程图:

重绘不会影响布局,但是当脚本触发了样式修改,而修改的部分是背景、字体颜色、边框颜色等,而这些修改也存在嵌套的节点链级相互影响,所以也是需要遍历操作,重绘不至于影响到布局,但也是一个相对损耗性能的操作,毕竟都需要DOM文档和JS引擎结构之间的桥梁通道来执行操作。不过重绘相对于重排来说就要快的多了。

7:css里不要有表达式expression

浏览器在解析页面时同时下载页面内容内容数据(异步:图片,src)

</ul>

二、解析HTML标签和CSS样式表、生成DOMTree和CSSTree

<html>

在前面的内容中解析了访问网站获取资源的基本原理,然后资源被访问到本地后怎么解析,解析时发什么的异步资源加载,同步资源加载,同步执行等一系列内容。然后在JS异步加载中提到了script.onload事件、script.onreadystatechange事件、script.readyState状态,然后还有document.readyState="interactive"文档状态和docuement.readyState="complete"文档状态。这些内容都发生在打开网页的那一瞬间,但是这一瞬间不只是检验物理配置的性能、浏览器内核的性能以及网络的性能,还关系到web开发者基于这些已定的基础平台的代码优化,所以我们有必要对这整个过程有非常清晰的理解,才能实现友好的程序设计。下面我们就通过JS时间线来描述这个过程如何发生的:

<span></span>

通常我们给某个服务器发送一个web请求时,首先返回的是一个HTML资源。假设这个资源的内部代码如下:<!DOCTYPE html>

1、HTML支持的组要资源类型

资源 资源管理类 HTML MainResource ===> CachedRawResource JavaScript CachedScript CSS CachedCSStyleSheet 图片 CachedImage SVG CachedSVGDocument CSS Shader CachedShader 视频、音频、字幕 CachedTextTrack 字体文件 CachedFont XSL样式表 CachedXSLStyleSheet

<li><img src=".../image/xxx.png" alt=""></li>

<img src=";

测试结果是外部JS的加载也会阻塞HTML解析构建DOMTree。所以结论是JS的加载和执行都会阻塞DOMTree的构建,接着问题又来了,我们前面提到过JS代码会操作DOM还会操作CSS,所以从理论上讲JS肯定得需要等到CSS加载解析完才会执行,CSS阻塞JS执行是肯定的,再思考CSS的加载会阻塞JS的加载吗?<!DOCTYPE html>

</p>

5.遇到img等外部内容数据,先正常解析DOM结构,然后浏览器异步加载src,并且继续解析文档。

console.log;//13

因为布局计算需要基于元素上下节点来进行,元素的大小和位置变化都有可能会影响到父级和子级的元素大小和位置变化,所以randerTree上的某个RanderObject的相关数据发生变化除了自身的layout()方法需要重新执行计算,还可能会触发上下级的节点的layout()方法的重新执行计算。

葡京正网网投,console.log(document.querySelectorAll;//NodeList []

<title>Title</title>

其实相对来说JS与CSS阻塞还是比较好理解的,毕竟还有可参考的数值和可视的图像信息,接下来的问题就只能依靠逻辑推理了。

除了脚本的影响外,还有可能是浏览器窗口发生产生变化导致全局的randerTree重新布局计算,另外如果脚本修改了全局的样式也同样可能会触发全局的重新布局计算。

<head>

2:尽量通过class来设计元素样式,切忌用style

<meta http-equiv="X-UA-Compatible" content="IE=edge">

3、资源加载器

</head>

<html>

<script src=".../javascripts/xxx.js" type="text/javascript"></script>

// 循环5秒钟

</body>

</script>

在WebKit中共有三种类型的资源加载器,分别是:

<script src=";

三、JS与CSS阻塞

4:权衡速度的平滑。比如实现一个动画,以1个像素为单位移动这样最平滑,但reflow就会过于频繁,CPU很快就会被完全占用。如果以3个像素为单位移动就会好很多。

var n =Number(new Date;

<p>

当请求协议指定可以取缓存数据,请求资源会先判断内存中是否有资源,然后将资源的信息通过HTTP报文一起发送给服务器,服务器通过报文判断缓存的资源是否是最新的,资源缓存是否超时来决定是否重新获取服务端的资源,如果不需要重新获取服务端的资源,服务器会返回状态码304,告诉浏览器取本地缓存资源。

<body>

资源的缓存机制是提高资源使用效率的有效方法。基本思想就是建立一个资源缓存池,当web需要请求资源时,会先从资源池中查找是否存在相应的资源,如果有的话就直接取缓存,如果没有就创建一个新的CachedResource子类的对象,并发送请求给服务器,请求回来的资源会被添加到资源池,并且将资源(数据信息:比如在资源池中的物理地址)设置到该资源的对象中去,以便下次使用。

3:实现元素的动画,对于经常要进行回流的组件,要抽离出来,它的position属性应当设为fixed或absolute

按照示例HTML解析流程图,根据编号顺序按照1-->1.1-->1.2-->1.3-->1.4-->2-->2.1-->2.1.1-->2.1.1.1-->2.1.2-->2.1.2.-->2.1.2.1-->2.1.2.2-->2.1.2.3-->2.2。用一句来表达这种解析原则就是一条道走到黑,开玩笑,但是的确很形象哈。CSS样式表解析和构建CSS树也同样使用这个原则。当DOMTree和CSSTree都构建完成以后就会被合并成渲染树(randerTree)。渲染树解析完毕以后就开始绘制页面。

布局

console.log(document.querySelectorAll;//NodeList [img.img2]

(减少重排与重绘的一些要点)

合并DOMTree和CSSTree生成randerTree

n2 = Number(new Date;

要说是JS时间线的话,可能不是很恰当,或者应该说是文档模型初始化构建过程的JS表示,能够操作DOM对象接口的语言有很多,这里就是用JS来表示DOM对象模型初始化的整个过程。

var n3 = Number(new Date;

<link type="text/css" rel="stylesheet" href="" />

console.log(Number(new Date;//外部CSS阻塞JS执行40~200毫秒 --- 注释外部CSS代码测试差值0~1毫秒

<div>

绘制

8:减少不必要的 DOM 层级(DOM depth)。改变 DOM 树中的一级会导致所有层级的改变,上至根部,下至被改变节点的子节点。这导致大量时间耗费在执行 reflow 上面。

loading - 载入中

发生重排/回流与重绘其本质上重新布局和构建randerTree,如果将DOM之前的执行过程理解为同步,这个时候浏览器转为事件取动的异步阶段,浏览器内核在构建randerTree的同时JS也会被事件取动参与修改文档的结构和样式,也是触发重排/回流与重绘行为的关键所在,而本质上做的事情就是重新计算布局和构建randerTree树,所以在解析重排与重绘之前先来了解以下布局计算和randerTree构建:

重绘

1:不要通过父级来改变子元素样式,最好直接改变子元素样式,改变子元素样式尽可能不要影响父元素和兄弟元素的大小和尺寸

<script>

如果说资源缓存和网络资源是浏览器要渲染页面的资源实体,那资源加载器就是为浏览器实现页面渲染提供资源数据的搬运工。前面的资源请求相当于就是资源地址寻址的过程,真正为渲染提供资源的过程是下面这样的:

JS时间线之十个环节:

葡京正网网投 22

本文由葡京网投哪个正规发布于新葡亰-前端,转载请注明出处:浏览器加载解析渲染网页原理,渲染机制

关键词:

上一篇:渲染机制,你先要知道这几点细节

下一篇:没有了