You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<html>
<head>
<title>Web page parsing</title>
</head>
<body>
<div>
<h1>Web page parsing</h1>
<p>This is an example Web page.</p>
</div>
</body>
</html>
网络的模型是同步的,浏览器解析文档,当遇到<script>标签的时候,会立即解析(执行)脚本,停止解析文档(停止DOM Tree的构建,因为 JS 可能会改动 DOM 和 CSS ,万一脚本内全删了后面的DOM,浏览器就白干活了。所以继续解析会造成浪费)。
如果脚本是外部的,会等待脚本下载完毕并执行完毕,再继续解析 HTML 文档。现在可以在 script 标签上增加属性 defer或者async,来使脚本的处理相对 DOM Tree 的构建是异步的。注意,如果脚本是内联在 html 文档内,无法更改脚本的执行顺序,只能是立即解析脚本,并停止 DOM Tree 的构建,直到脚本执行完毕。像这样的脚本:
一个问题
从用户输入浏览器输入url到页面最后呈现 有哪些过程?
考的是基本网络原理,和浏览器加载css,js过程。
答案大致如下:
如果文档中有资源 重复6 7 8 动作 直至资源全部加载完毕
以上答案基本简述了一个网页基本的响应过程背后的原理。
但这只是浏览器获取数据的部分,至于浏览器拿到数据之后,怎么渲染页面的呢。
这是一个渐进的过程。为达到更好的用户体验,呈现引擎会力求尽快将内容显示在屏幕上。它不必等到整个 HTML 文档解析完毕之后,就会开始构建呈现树和设置布局。在不断接收和处理来自网络的其余内容的同时,呈现引擎会将部分内容解析并显示出来。
一、HTML解析
HTML Parser的任务是将HTML标记解析成DOM Tree。(文档对象模型)
这个解析可以参考React解析DOM的过程,但是这里面有很多别的规则和操作,比如容错机制,识别
</br>
和<br>
等等。例如:
将文本的HTML文档,提炼出关键信息---嵌套层级的树形结构。便于计算拓展,这就是HTML Parser的作用。
二、CSS解析
CSS Parser将CSS解析成Style Rules,Style Rules也叫CSSOM(CSS Object Model,样式对象模型)。
StyleRules也是一个树形结构,根据CSS文件整理出来的类似DOM Tree的树形结构:
于HTML Parser相似,CSS Parser作用就是将很多个CSS文件中的样式合并解析出具有树形结构Style Rules。(Style Rules则包含选择器和声明对象,以及其他与 CSS 语法对应的对象)
脚本处理和样式表的顺序
1. CSS 不会阻塞 DOM 的解析(即HTML的解析,CSS 不会阻塞 DOM Tree的构建)
浏览器是解析 DOM 生成 DOM Tree,结合 CSS 生成的 CSS Tree,最终组成render tree,再渲染页面。由此可见,在此过程中 CSS 完全无法影响 DOM Tree,因而无需阻塞DOM解析。
即当遇到
<link>
标签,尽管外部CSS下载需要3s,但这个过程中,浏览器不会傻等着CSS下载完,而是会解析DOM的。然而,DOM Tree 和 CSS Tree 会组合成 render tree,那 CSS 会不会页面阻塞渲染呢?
2. CSS 阻塞页面渲染
原因:如果CSS 不会阻塞页面渲染,那么 CSS 文件下载之前,浏览器就会渲染出一种样式的页面, CSS 文件下载完成之后样式改变了又渲染出另一种样式的页面。导致页面首先会呈现出一个原始的模样,待CSS下载完之后又突然变了一个模样。用户体验可谓极差,而且渲染是有成本的。
因此,基于性能与用户体验的考虑,浏览器会尽量减少渲染的次数,CSS 顺理成章地阻塞页面渲染,直至 CSSOM 构建完毕。
由于 CSS 不会阻塞 HTML 文档的解析,因此在下载 CSS 文件的时候,意味着
<link>
和<script>
等其他的外部文件都会提前并行下载(加载)。即使 JS 会阻塞 html 文档的解析,但浏览器会"偷看"DOM,预先下载相关资源。总之,html 文档中的所有外部资源总是提前加载的(并行下载)(浏览器不会傻等到解析到那里时才下载)。我们知道 CSSOM 的构建不会阻塞 DOM 的解析,并且外部资源都会提前加载(下载)。需要注意的是,Js 的执行会等到前面 CSSOM 的构建完毕才开始。
原因:如果脚本的内容是获取元素的样式,宽高等 CSS 控制的属性,浏览器是需要计算的,也就是依赖于CSS。所以浏览器需要前面所有的样式下载完后,再执行JS。
优化点(CSS 优化):
<script>
中基本内容不是用来获取 DOM 元素或者 CSS样式属性的话,<script>
与<link>
同时在头部的话,让<script>
标签处于<link>
之前。(如果<link>
的内容下载更快的话,是没影响的,但反过来的话,JS就要等待了,然而这些等待的时间是完全不必要的)@import
【不使用
@import
】比如一个 CSS 文件index.css包含了以下内容:@import url("reset.css")。那么浏览器就必须先把index.css下载、解析和执行后,才下载、解析和执行第二个文件reset.css。
【为什么要避免层级或过度限制的CSS】
浏览器对 CSS 选择器是从右到左解析。
.nav h3 a{font-size: 14px;}
首先找到所有的a,沿着a的父元素查找h3,然后再沿着h3,查找.nav。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素html都没有匹配,则不再遍历这条路径,从下一个a开始重复这个查找匹配(只要页面上有多个最右节点为a)。简洁的选择器不仅可以减少css文件大小,提高页面的加载性能,浏览器解析时也会更加高效,也会提高开发人员的开发效率,降低了维护成本。过度的嵌套会导致代码变得臃肿、沉余、复杂,导致 CSS 文件体积变大,造成性能浪费,影响渲染的速度,而且过于依赖 HTML 文档结构。这样的 CSS 样式,维护起来,极度麻烦,如果以后要修改样式,可能要使用!important覆盖。
【CSS中的可继承属性与不可继承属性】:
渲染树(Render-Tree)的关键渲染路径中,要求同时具有 DOM 和 CSSOM,之后才会构建渲染树。即,HTML 和 CSS 都是阻塞渲染的资源。HTML 显然是必需的,因为包括我们希望显示的文本在内的内容,都在 DOM 中存放,那么可以从 CSS 上想办法。
最容易想到的当然是精简 CSS 并尽快提供它。除此之外,还可以用媒体类型(media type)和媒体查询(media query)来解除对渲染的阻塞。
第一个资源会加载并阻塞。
第二个资源设置了媒体类型,会加载但不会阻塞,print 声明只在打印网页时使用。
第三个资源提供了媒体查询,会在符合条件时阻塞渲染。
3. JS 阻塞 DOM 解析
网络的模型是同步的,浏览器解析文档,当遇到
<script>
标签的时候,会立即解析(执行)脚本,停止解析文档(停止DOM Tree的构建,因为 JS 可能会改动 DOM 和 CSS ,万一脚本内全删了后面的DOM,浏览器就白干活了。所以继续解析会造成浪费)。如果脚本是外部的,会等待脚本下载完毕并执行完毕,再继续解析 HTML 文档。现在可以在 script 标签上增加属性 defer或者async,来使脚本的处理相对 DOM Tree 的构建是异步的。注意,如果脚本是内联在 html 文档内,无法更改脚本的执行顺序,只能是立即解析脚本,并停止 DOM Tree 的构建,直到脚本执行完毕。像这样的脚本:
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
此图告诉我们以下几个要点:
4. 浏览器遇到
<script>
标签时,会触发页面渲染原因:浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM元素信息。
例子:
答案:先浅绿色,再浅灰色,最后粉红。(浏览器渲染速度较大,只能微微看到两面的颜色一闪而过)
即浏览器遇到
<script>
且没有 defer 或 async 属性的 标签时,会触发页面渲染,因而如果前面CSS资源尚未加载完毕时,浏览器会等待它加载完毕在执行脚本。5. Speculative parsing(预解析/预加载)
当执行脚本时,其它线程会解析剩下的文档,找出里面的外部资源(script/style/img)来提前加载(可以并行加载)。这种解析只是去查找需要加载的外部资源,不会修改content tree。
所以我们可以看到多个外部资源并行下载。
6. document.createElement
使用 document.createElement 创建的 script 默认是异步的,示例如下。
所以,通过动态添加 script 标签引入 JavaScript 文件默认是不会阻塞页面的。如果想同步执行,需要将 async 属性人为设置为 false。
脚本解析会将脚本中改变 DOM 和 CSS 的地方分别解析出来,追加到 DOM Tree 和 Style Rules 上。
优化方案(对 JS 文件的优化)
<script>
脚本放在 HTML 文档底部(</body>
前),或者给<script>
增加async
ordefer
属性。<script>
会触发页面的渲染,所以不要把 css文件放在 脚本之后。)三、Render Tree(渲染树包含带有视觉属性(如颜色和尺寸)的矩形们)
这是由可视化元素按照其显示顺序而组成的树,也是文档的可视化表示。它的作用是保证按照正确的顺序来绘制内容。
渲染树的每个节点(renderer)代表一个矩形区域——对应DOM元素的CSS Box。
四、Layout(回流:Reflow)
在渲染树创建后进入 Layout 阶段,给渲染树的每个节点设置在屏幕上的位置信息
renderer在创建完成并添加到render tree时,并不包含 位置和大小 信息。计算这些值的过程称为布局或重排(Layout/Reflow)。
五、Paint (Repaint)
Paint 阶段,通过 UI backend 绘制 render tree 到屏幕。
一般来说,可以把普通文档流看成一个图层。特定的属性可以生成一个新的图层。不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。但也不能生成过多的图层,会引起反作用。
通过以下几个常用属性可以生成新图层
3D 变换:translate3d、translateZ
will-change
video、iframe 标签
通过动画实现的 opacity 动画转换
position: fixed
重绘与回流
重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘
回流是布局或者几何属性需要改变就称为回流。
回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流。
减少重绘和回流:
References
原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的
CSS选择器从右向左的匹配规则
浏览器的工作原理
从浏览器输入一个 url 到页面渲染,涉及的知识点及优化点
浏览器中输入url后发生了什么
The text was updated successfully, but these errors were encountered: