浏览器页面渲染机制

分享目的: 解释浏览器如何将 HTML、CSS 和 JavaScript 转换为咱们能够与之交互的网站,了解这个过程,能够帮助咱们优化 Web 应用程序,从而得到更快的速度和更好的性能。

问题: 浏览器如何渲染网站? (接下来会解构这个过程,可是首先,有必要了解一些基础概念)

Web 浏览器是一种软件,它从远程服务器(或者本地磁盘)加载文件并将其显示——使用户能够与之交互。浏览器中有一个软件叫浏览器引擎。在不一样的浏览器中,浏览器的某个部分会根据它接收到的文件肯定显示什么,这就是所谓的浏览器引擎。浏览器引擎是每一种主流浏览器的核心软件组件,不一样的浏览器开发商用不一样的名字来称呼他们的引擎。javascript

1. html解析

  • 接收信息
    数据是以“数据包”的形式经过互联网发送,而数据包以字节为单位。当你编写一些 HTML、CSS 和 JS,并试图在浏览器中打开 HTML 文件时,浏览器会从你的硬盘(或网络)中读取 HTML 的原始字节。
  • 计算机接收到字节数据
    浏览器读取的是原始数据字节,而不是你编写的代码的实际字符。浏览器读取的是原始数据字节,而不是你编写的代码的实际字符。
  • 从 HTML 的原始字节到 DOM,浏览器对象须要处理的是文档对象模型(DOM)对象。那么,DOM 对象是从何而来的呢?首先,将原始数据字节转换为字符。(Bytes => haracters)
  • 从字节到字符
    这一点,你能够经过你所编写的代码的字符看到。这种转换是基于 HTML 文件的字符编码完成的。至此,浏览器已经从原始数据字节转换为文件中的实际字符。但这不是最终的结果。这些字符会被进一步解析为一些称为“标记(token)”的东西。(Bytes => haracters => Tokens···)
  • 从字符到标记
    那么,这些标记是什么?文本文件中的一堆字符对浏览器引擎而言没什么用处。若是没有这个标记化过程,那么这一堆堆字符只会生成一系列毫无心义的文本,即 HTML 代码——不会生成一个真正的网站。 当你保存一个扩展名为.html 的文件时,就向浏览器引擎发出了把文件解析为 HTML 文档的信号。浏览器“解释”这个文件的方式是首先解析它。在解析过程当中,特别是在标记化过程当中,浏览器会解析 HTML 文件中的每一个开始和结束“标签(tag)”。解析器能够识别尖括号中的每一个字符串,如“< html>”、“< p>”

但标记还不是最终的结果。标记化完成后,接下来,标记将被转换为节点。你能够将节点看做是具备特定属性的不一样对象。实际上,更好的解释是,将节点看做是文档对象树中的独立实体。但节点仍然不是最终结果。 如今,让咱们看一下最后一点。在建立好以后,这些节点将被连接到称为DOM 的树数据结构中。DOM 创建起了父子关系、相邻兄弟关系等。在这个 DOM 对象中,每一个节点之间都创建了关系。如今,这是咱们可使用的东西了。css

  • 标记
    但标记还不是最终的结果。标记化完成后,接下来,标记将被转换为节点。你能够将节点看做是具备特定属性的不一样对象。实际上,更好的解释是,将节点看做是文档对象树中的独立实体。但节点仍然不是最终结果。
  • DOM (Bytes => haracters => Tokens => Node => DOM) 让咱们看一下最后一点。在建立好以后,这些节点将被连接到称为 DOM 的树数据结构中。DOM 创建起了父子关系、相邻兄弟关系等。在这个 DOM 对象中,每一个节点之间都创建了关系。这个时候,是浏览器须要的东西了。

2.css解析

这个是咱们很常见的写法html

<!DOCTYPE html>
<html> <head> <link rel="stylesheet" type="text/css" href="test.css" /> </head> <body> </body> </html> 复制代码

当浏览器接收到原始数据字节并启动 DOM 构建过程时,它还会发出请求来获取连接的 test.css 样式表。当浏览器开始解析 HTML 时,在找到 css 文件的连接标签的同时,它会发出请求来获取它。可能你已经猜到,浏览器仍是接收 CSS 数据的原始字节,从互联网或是本地磁盘。java

浏览器如何处理这些 CSS 数据的原始字节?

当浏览器接收到 CSS 的原始字节时,会启动一个和处理 HTML 原始字节相似的过程。就是说,原始数据字节被转换成字符,而后标记,而后造成节点,最后造成树结构。 什么是树结构?大多数人都知道 DOM 这个词。一样,也有一种 CSS 树结构,,浏览器不能使用 HTML 或 CSS 的原始字节。必须将其转换成它能识别的形式,也就是这些树形结构。浏览器

DOM + CSSOM = 渲染树

渲染树包含页面上全部关于可见 DOM 内容的信息以及不一样节点所需的全部 CSSOM 信息。注意,若是一个元素被 CSS 隐藏,例如使用 display; none,那么节点就不会包含在渲染树中。隐藏元素会出如今 DOM 中,但不会出如今渲染树中。这是由于渲染树结合了来自 DOM 和 CSSOM 的信息,因此它知道不能把隐藏元素包含在树中。服务器

元素展现

咱们已经获得了在屏幕上显示元素所需的全部信息。咱们只要把它展现给用户。这就是这个阶段的所有工做。有了元素内容(DOM)、样式(CSSOM)和计算得出的元素的精确布局信息,浏览器如今就能够将节点逐个“绘制”到屏幕上了。元素能够呈如今屏幕上了!markdown


渲染阻塞资源

通俗的解释为有东西阻止了屏幕上节点的实际绘制,在成功绘制以前,必须构造 DOM 和 CSSOM,所以,HTML 和 CSS 都是渲染阻塞资源。网络

  • JavaScript 如何执行?
    一个经常使用的 Web 应用程序确定会使用一些 JavaScript。这是必定的。JavaScript 的“问题”在于你可使用 JavaScript 修改页面的内容和样式。经过这种方式,你能够从 DOM 树中删除元素和添加元素,还能够经过 JavaScript 修改元素的 CSSOM 属性。这很方便,可是同时也带来了弊端
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <p>浏览器页面渲染机制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
复制代码

这是一个很是常见的文档。样式表 style.css简单定义样式:数据结构

* {
  font-size: 20px;
}
body {
  background-color: antiquewhite;
}
复制代码

一段简单的文本和图像呈如今屏幕上。async

根据前面的解释,浏览器从磁盘(或网络)读取 HTML 文件的原始字节并将其转换为字符。字符被进一步解析为标记。当解析器遇到< link rel="stylesheet" href="style.css">时,就会请求获取 CSS 文件 style.css。DOM 构造继续进行,当 CSS 文件返回一些内容后,CSSOM 构造就开始了。

  • 引入 JavaScript
    每当浏览器遇到脚本标签时,DOM 构造就会暂停!整个 DOM 构建过程都将中止,直到脚本执行完成。JavaScript 能够同时修改 DOM 和 CSSOM。因为浏览器不肯定特定的 JavaScript 会作什么,因此它采起的预防措施是中止整个 DOM 构造。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <p id="title">浏览器页面渲染机制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
  <script>
      let title = document.getElementById("title");
      console.log("title is: ", title);
  </script>
</body>
</html>
复制代码

当把js放到元素以前的话

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>testRander</title>
 <link rel="stylesheet" href="style.css">
</head>
<body>
   <script>
       let title = document.getElementById("title");
       console.log("title is: ", title);
   </script>
 <p id="title">浏览器页面渲染机制</p>
 <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
复制代码

当脚本试图访问一个 id 为 header 的 DOM 节点时,因为 DOM 尚未完成对文档的解析,因此它还不存在。这把咱们带到了另外一个重要的问题。脚本的位置很重要。

在默认状况下,每一个脚本都是一个解析器阻断器!DOM 的构建老是会被打断。不过,有一种方法能够改变这种默认行为。若是将 async 关键字添加到脚本标签中,那么 DOM 构造就不会中止。DOM 构造将继续,脚本将在下载完成并准备就绪后执行。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <script src="test.js" async></script>
  <p id="title">浏览器页面渲染机制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
复制代码

把js放入test.js中进行引入

let title = document.getElementById("title");
console.log("title is: ", title);
复制代码

这样DOM的构建就不会中止,脚本在构造完成后执行。

相关文章
相关标签/搜索