热门标签 | 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 的实行,由于浏览器都邑有预先扫描器)

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


推荐阅读
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
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社区 版权所有