热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浏览器衬着机制

本文示例源代码请戳github博客,提议人人着手敲敲代码。媒介浏览器衬着页面的历程从耗时的角度,浏览器要求、加载、衬着一个页面,时刻花在下面五件事变上:DNS查询TCP衔接HTTP

本文示例源代码请戳
github博客,提议人人着手敲敲代码。

媒介

浏览器衬着页面的历程

从耗时的角度,浏览器要求、加载、衬着一个页面,时刻花在下面五件事变上:

  1. DNS 查询
  2. TCP 衔接
  3. HTTP 要求即响应
  4. 服务器响应
  5. 客户端衬着

本文议论第五个部份,即浏览器对内容的衬着,这一部份(衬着树构建、规划及绘制),又能够分为下面五个步骤:

  1. 处置惩罚 HTML 标记并构建 DOM 树。
  2. 处置惩罚 CSS 标记并构建 CSSOM 树
  3. 将 DOM 与 CSSOM 兼并成一个衬着树。
  4. 依据衬着树来规划,以盘算每一个节点的多少信息。
  5. 将各个节点绘制到屏幕上。

须要邃晓,这五个步骤并不一定一次性递次完成。假如 DOM 或 CSSOM 被修正,以上历程须要反复实行,如许才盘算出哪些像素须要在屏幕上举行从新衬着。现实页面中,CSS 与 Javascript 往往会屡次修正 DOM 和 CSSOM。

1、浏览器的线程

在细致申明之前我们来看一下浏览器线程。这将有助于我们明白后续内容。

浏览器是多线程的,它们在内核制控下相互配合以坚持同步。一个浏览器最少完成三个常驻线程:Javascript 引擎线程,GUI 衬着线程,浏览器事宜触发线程。

  • GUI 衬着线程:担任衬着浏览器界面 HTML 元素,当界面须要重绘(Repaint)或由于某种操纵激发回流(reflow)时,该线程就会实行。在 Javascript 引擎运转剧本时期,GUI 衬着线程都是处于挂起状况的,也就是说被”凝结”了。
  • Javascript 引擎线程:重要担任处置惩罚 Javascript 剧本顺序。
  • 定时器触发线程:浏览器定时计数器并非由 Javascript 引擎计数的, Javascript 引擎是单线程的, 假如处于壅塞线程状况就会影响记计时的正确, 因而浏览器经由过程零丁线程来计时并触发定时。
  • 事宜触发线程:当一个事宜被触发时该线程会把事宜添加到待处置惩罚行列的队尾,守候 JS 引擎的处置惩罚。这些事宜包含当前实行的代码块如定时使命、浏览器内核的其他线程如鼠标点击、AJAX 异步要求等。由于 JS 的单线程关联一切这些事宜都得列队守候 JS 引擎处置惩罚。定时块任何和 ajax 要求等这些异步使命,事宜触发线程只是在抵达定时时刻或许是 ajax 要求胜利后,把回调函数放到事宜行列当中。
  • 异步 HTTP 要求线程:在 XMLHttpRequest 在衔接后是经由过程浏览器新开一个线程要求, 将检测到状况变动时,假如设置有回调函数,异步线程就发生状况变动事宜放到 Javascript 引擎的处置惩罚行列中守候处置惩罚。在提议了一个异步要求时,http 要求线程则担任去要求服务器,有了响应今后,事宜触发线程再把回到函数放到事宜行列当中。
2、构建DOM树与CSSOM树

浏览器从收集或硬盘中取得HTML字节数据后会经由一个流程将字节剖析为DOM树:

  • 编码: 先将HTML的原始字节数据转换为文件指定编码的字符。
  • 令牌化: 然后浏览器会依据HTML范例来将字符串转换成种种令牌(如如许的标签以及标签中的字符串和属性等都邑被转化为令牌,每一个令牌具有迥殊寄义和一组划定规矩)。令牌记录了标签的最先与终了,经由过程这个特征能够轻松推断一个标签是不是为子标签(假设有两个标签,当标签的令牌还未碰到它的终了令牌就碰见了标签令牌,那末就是的子标签)。
  • 天生对象: 接下来每一个令牌都邑被转换成定义其属性和划定规矩的对象(这个对象就是节点对象)
  • 构建终了: DOM树构建完成,全部对象鸠合就像是一棵树形构造。能够有人会迷惑为何DOM是一个树形构造,这是由于标签之间含有庞杂的父子关联,树形构造恰好能够诠释这个关联(CSSOS同理,层叠款式也含有父子关联。比方: div p {font-size: 18px},会先寻觅一切p标签并推断它的父标签是不是为div以后才会决议要不要采纳这个款式举行衬着)。

全部DOM树的构建历程实在就是: 字节 -> 字符 -> 令牌 -> 节点对象 -> 对象模子,
下面将经由过程一个示例HTML代码与配图更抽象地诠释这个历程。








Hello web performance students!




《浏览器衬着机制》

当上述HTML代码碰见标签时,浏览器会发送要求取得该标签中标记的CSS文件(运用内联CSS能够省略要求的步骤进步速率,但没有必要为了这点速率而丧失了模块化与可维护性),style.css中的内容以下:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

浏览器取得外部CSS文件的数据后,就会像构建DOM树一样最先构建CSSOM树,这个历程没有什么迥殊的差异。
《浏览器衬着机制》

3、构建衬着树

在构建了DOM树和CSSOM树以后,浏览器只是具有了两个相互自力的对象鸠合,DOM树形貌了文档的构造与内容,CSSOM树则形貌了对文档运用的款式划定规矩,想要衬着出页面,就须要将DOM树与CSSOM树连系在一同,这就是衬着树。
《浏览器衬着机制》

  • 浏览器会先从DOM树的根节点最先遍历每一个可见节点(不可见的节点天然就没必要衬着到页面了,不可见的节点还包含被CSS设置了display: none属性的节点,值得注重的是visibility: hidden属性并不算是不可见属性,它的语义是隐蔽元素,但元素依旧占有着规划空间,所以它会被衬着成一个空框)
  • 对每一个可见节点,找到其适配的CSS款式划定规矩并运用。
  • 衬着树构建完成,每一个节点都是可见节点而且都含有其内容和对应划定规矩的款式。
4、规划与绘制

CSS采纳了一种叫做盒子模子的头脑模子来示意每一个节点与其他元素之间的间隔,盒子模子包含外边距(Margin),内边距(Padding),边框(Border),内容(Content)。页面中的每一个标签实在都是一个个盒子

《浏览器衬着机制》
规划阶段会从衬着树的根节点最先遍历,然后肯定每一个节点对象在页面上的确实大小与位置,规划阶段的输出是一个盒子模子,它会精确地捕捉每一个元素在屏幕内的确实位置与大小,一切相对的测量值也都邑被转换为屏幕内的相对像素值。








Hello world!



《浏览器衬着机制》

当Layout规划事宜完成后,浏览器会马上发出Paint Setup与Paint事宜,最先将衬着树绘制成像素,绘制所需的时刻跟CSS款式的庞杂度成正比,绘制完成后,用户就能够看到页面的终究显现结果了。

我们对一个网页发送要求并取得衬着后的页面能够也就经由了1~2秒,但浏览器实在已做了上述所讲的异常多的事情,总结一下浏览器症结衬着途径的全部历程:

  • 处置惩罚HTML标记数据并天生DOM树。
  • 处置惩罚CSS标记数据并天生CSSOM树。
  • 将DOM树与CSSOM树兼并在一同天生衬着树。
  • 遍历衬着树最先规划,盘算每一个节点的位置信息。
  • 将每一个节点绘制到屏幕。
5、外部资本是怎样要求的

为了直观的视察浏览器加载和衬着的细节,当地用nodejs搭建一个简朴的HTTP Server。
index.js

const http = require('http');
const fs = require('fs');
const hostname = '127.0.0.1';
const port = 8080;
http.createServer((req, res) => {
if (req.url == '/a.js') {
fs.readFile('a.js', 'utf-8', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/plain'});
setTimeout(function () {
res.write(data);
res.end()
}, 5000)
})
} else if (req.url == '/b.js') {
fs.readFile('b.js', 'utf-8', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(data);
res.end()
})
} else if (req.url == '/style.css') {
fs.readFile('style.css', 'utf-8', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/css'});
res.write(data);
res.end()
})
} else if (req.url == '/index.html') {
fs.readFile('index.html', 'utf-8', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end()
})
}
}).listen(port, hostname, () => {
console.log('Server running at ' + hostname + ':' + port);
});

index.html









没有 defer 或 async,浏览器会马上加载并实行指定的剧本,也就是说不守候后续载入的文档元素,读到就加载并实行。

  • 状况2 (异步下载)

async 属性示意异步实行引入的 Javascript,与 defer 的区分在于,假如已加载好,就会最先实行——不管现在是 HTML 剖析阶段照样 DOMContentLoaded 触发以后。须要注重的是,这类体式格局加载的 Javascript 依旧会壅塞 load 事宜。换句话说,async-script 能够在 DOMContentLoaded 触发之前或以后实行,但一定在 load 触发之前实行。

  • 状况3 (耽误实行)

defer 属性示意耽误实行引入的 Javascript,即这段 Javascript 加载时 HTML 并未住手剖析,这两个历程是并行的。全部 document 剖析终了且 defer-script 也加载完成以后(这两件事变的递次无关),会实行一切由 defer-script 加载的 Javascript 代码,然后触发 DOMContentLoaded 事宜。

defer 与比拟一般 script,有两点区分:

  • 载入 Javascript 文件时不壅塞 HTML 的剖析,实行阶段被放到 HTML 标签剖析完成以后。
  • 在加载多个JS剧本的时刻,async是无递次的加载,而defer是有递次的加载。
8、css文件的影响

服务端将style.css的响应也设置耽误。

fs.readFile('style.css', 'utf-8', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/css'});
setTimeout(function () {
res.write(data);
res.end()
}, 5000)
})












222222


3333333






能够看出来,css文件不会壅塞HTML剖析,然则会壅塞衬着,致使css文件未下载完成之前已剖析好html也没法先显现出来。

我们把css调解到尾部











222222


3333333






这是页面能够衬着了,然则没有款式。直到css加载完成

以上我们能够简朴总结。

  • CSS 放在 head 中会壅塞页面的衬着(页面的衬着会比及 css 加载完成)
  • CSS 壅塞 JS 的实行 (由于 GUI 线程和 JS 线程是互斥的,由于有能够 JS 会操纵 CSS)
  • CSS 不壅塞外部剧本的加载(不壅塞 JS 的加载,但壅塞 JS 的实行,由于浏览器都邑有预先扫描器)

参考
浏览器衬着历程与机能优化
聊聊浏览器的衬着机制
你不知道的浏览器页面衬着机制


推荐阅读
  • 本文详细介绍了网络存储技术的基本概念、分类及应用场景。通过分析直连式存储(DAS)、网络附加存储(NAS)和存储区域网络(SAN)的特点,帮助读者理解不同存储方式的优势与局限性。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 深入探讨CPU虚拟化与KVM内存管理
    本文详细介绍了现代服务器架构中的CPU虚拟化技术,包括SMP、NUMA和MPP三种多处理器结构,并深入探讨了KVM的内存虚拟化机制。通过对比不同架构的特点和应用场景,帮助读者理解如何选择最适合的架构以优化性能。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 深入解析 Spring Security 用户认证机制
    本文将详细介绍 Spring Security 中用户登录认证的核心流程,重点分析 AbstractAuthenticationProcessingFilter 和 AuthenticationManager 的工作原理。通过理解这些组件的实现,读者可以更好地掌握 Spring Security 的认证机制。 ... [详细]
  • yikesnews第11期:微软Office两个0day和一个提权0day
    点击阅读原文可点击链接根据法国大选被黑客干扰,发送了带漏洞的文档Trumps_Attack_on_Syria_English.docx而此漏洞与ESET&FireEy ... [详细]
  • 访问一个网页的全过程
    准备:DHCPUDPIP和以太网启动主机,用一根以太网电缆连接到学校的以太网交换机,交换机又与学校的路由器相连.学校的这台路由器与一个ISP链接,此ISP(Intern ... [详细]
  • 本文详细探讨了HTTP 500内部服务器错误的成因、解决方案及其在Web开发中的影响。通过对具体案例的分析,帮助读者理解并解决此类问题。 ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
  • 图数据库中的知识表示与推理机制
    本文探讨了图数据库及其技术生态系统在知识表示和推理问题上的应用。通过理解图数据结构,尤其是属性图的特性,可以为复杂的数据关系提供高效且优雅的解决方案。我们将详细介绍属性图的基本概念、对象建模、概念建模以及自动推理的过程,并结合实际代码示例进行说明。 ... [详细]
  • 深入理解Java泛型:JDK 5的新特性
    本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 本文探讨了如何在 PHP 的 Eloquent ORM 中实现数据表之间的关联查询,并通过具体示例详细解释了如何将关联数据嵌入到查询结果中。这不仅提高了数据查询的效率,还简化了代码逻辑。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文将深入探讨PHP编程语言的基本概念,并解释PHP概念股的含义。通过详细解析,帮助读者理解PHP在Web开发和股票市场中的重要性。 ... [详细]
author-avatar
帅哥大香蕉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有