浏览器页面加载解析渲染机制

简介: 为什么要了解浏览器加载、解析、渲染这个过程?了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以最快的速度将文件加载完毕。了解浏览器如何进行解析,我们可以在构建DOM结构,组织css选择器时,选择最优的写法,提高浏览器的解析速率。
为什么要了解浏览器加载、解析、渲染这个过程?

了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以最快的速度将文件加载完毕。

了解浏览器如何进行解析,我们可以在构建DOM结构,组织css选择器时,选择最优的写法,提高浏览器的解析速率。

了解浏览器如何进行渲染,明白渲染的过程,我们在设置元素属性,编写js文件时,可以减少”重绘“”重新布局“的消耗。

这三个过程在实际进行的时候又不是完全独立,而是会有交叉。会造成一边加载,一边解析,一边渲染的工作现象。

浏览器是如何进行加载、解析、渲染的呢?

1.用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址,找到后,系统会向对应IP地址的网络服务器发送一个http请求。

2.网络服务器解析请求,并发送请求给数据库服务器。

3.数据库服务器将请求的资源返回给网络服务器,网络服务器解析数据,并生成html文件,放入http response中,返回给浏览器。

4.浏览器解析 http response。
1~4步骤需要了解HTTP协议。
访问服务器端可能遭遇的问题:如果网络服务器无法获取数据库服务器返回的资源文件(http response 404),或者由于并发原因暂时无法处理用户的http请求(http response 500)

5.浏览器解析 http response后,需要下载html文件,以及html文件内包含的外部引用文件,及文件内涉及的图片或者多媒体文件。

 

加载

即为获取资源文件的过程,不同浏览器,以及他们的不同版本在实现这一过程时,会有不同的实现效果(资源间互相阻塞),。(需要学习使用timeline来做测试,我还不太会用,学会了在上文。)

<!DOCTYPE html>
<html>
     <head> <meta charset="utf-8"> <link rel="stylesheet" href="test.css" type="text/css" /> <script src="test.js" type="text/javascript"></script> </head> <body> <p>阻塞</p> <img src="test.jpg" /> </body> </html>

加载过程中遇到外部css文件,浏览器另外发出一个请求,来获取css文件。
遇到图片资源,浏览器也会另外发出一个请求,来获取图片资源。这是异步请求,并不会影响html文档进行加载,但是当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。

原因:JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。
办法:可以将外部引用的js文件放在</body>前。

虽然css文件的加载不影响js文件的加载,但是却影响js文件的执行,即使js文件内只有一行代码,也会造成阻塞。

原因:可能会有 var width = $('#id').width(),这意味着,js代码执行前,浏览器必须保证css文件已下载和解析完成。这也是css阻塞后续js的根本原因。
办法:当js文件不需要依赖css文件时,可以将js文件放在头部css的前面。

当然除了,<link href="" />这种形式,内部<style></style>这种样式定义,在考虑阻塞时也要考虑。
以上对于代码布局对文档加载的影响是比较基础的,随着浏览器的升级,以及js技术的应用,html的发展,web性能也会逐渐提高。
列举一下,以后可以逐一扩充一下:

  • 不要在外部调用的js文件中调用运行时间较长的函数,如果一定要用,可以使用setTimeout函数。

    为什么呢?

    1. 浏览器GUI渲染线程
    2. javascript引擎线程
    3. 浏览器定时器触发线程(setTimeout)
    4. 浏览器事件触发线程
    5. 浏览器http异步请求线程(.jpg <link />这类请求)
      原因:浏览器有以上五个常驻线程
      发现第3个线程,我们便知道,如果在js内使用setTimeout()那么会调用另一个线程。
      注意:这里也涉及到 阻塞 的现象,当js引擎线程(第二个)进行时,会挂起其他一切线程,这个时候3、4、5这三类线线程也会产生不同的异步事件(这句话不懂啊),由于 javascript引擎线程为单线程,所以代码都是先压到队列,采用先进先出的方式运行,事件处理函数,timer函数也会压在队列中,不断的从队头取出事件,这就叫:javascript-event-loop。
  • 现代浏览器存在 prefetch 优化,浏览器会另外开启线程,提前下载js、css文件,需要注意的是,预加载js并不会改变dom结构,他将这个工作留给主加载。

  • 预加载网页,利用空余时间来提前加载该网页的后续网页。
    <link rel="prefetch" href="http://">
  • 为js脚本添加defer属性,使得浏览器不等js脚本加载执行完,就加载后面的图片。既然图片资源都已经加载出来了,就不要在js内写document.write啦。
    <script defer="true" src="JavaScript.js" type="text/javascript"/>

解析

解析的概念有些多,需要另写一篇文章。于是我就先简单的写一下。

  • html文档解析生成解析树即dom树,是由dom元素及属性节点组成,树的根是document对象。

    DOM:文档对象模型的缩写,是html文档的对象表示,作为html的外部接口供js调用。

    document.getElementById('test').style.display="none";//通过dom接口将id为test的display值设为none。

  • css解析将css文件解析为样式表对象。该对象包含css规则,该规则包含选择器和声明对象。

css解析.png
css解析.png
  • js解析因为文件在加载的同时也进行解析,详看js加载部分。

渲染

即为构建渲染树的过程,他是原来DOM树的可视化表示,构建这棵树是为了以正确的顺序绘制文档内容。
渲染树和DOM树的关系,不可见的dom元素(<head>…</head> display=none)不会被插入渲染树中。还有像一些节点的位置为绝对或浮动定位(需要css知识理解),这些节点会在文本流之外,因此会在两棵树上的不同位置,渲染树标识出真实的位置,并用一个占位结构标识出他们原来的位置。

渲染最大的一个困难就是为每一个dom节点计算符合他的最终样式。
  • 为每一个元素查找到匹配的样式规则,需要遍历整个规则表。关于遍历规则表的方法,我之前理解错啦。
     #test p{ color:#999999}
    正解:遍历是自右向左,也就是先查询到p元素,再找到上一级id为test的元素。之前的理解正好相反。这样发现,遍历的效率好低。
    为什么:可以去看之前css解析时,生成的样式对象,遍历的顺序,自然是从树的低端向上遍历。

计算样式的一些困难:

  1. 样式数据是非常大的结构,保存这样是的数据是很耗内存的。
  2. 选择器迭代太深,造成太多的无用遍历。
  3. 样式规则涉及非常复杂的级联,定义了规则的层次(理解:<head>里引用的外部样式表,会被局部样式表中同一属性的设置取代。还有例如body内对font的设置本来会应用于孩子元素,但是如果body的孩子元素定义font属性,则会被后者取代)。

解决办法:共享样式数据。(元素可以共享样式数据的条件就是他们的状态是”一致“的。)

webkit渲染

计算样式并生成渲染对象的过程为attachment,每个dom节点有一个attach方法,attachment的过程是同步的,调用新节点的attach方法插入到dom树中。
parser:解析, Render Tree:渲染树 Layout:安排布局

webkit主流程.png
webkit主流程.png

渲染过程中,webkit使用一个标志位标志所有顶层样式都已经被加载完毕,如果dom元素进行attach时,css元素并没有被加载完毕,则放置占位符,并在文档中标记,当样式表加载完毕,则重新进行计算。
说明,文档的渲染还是要等待顶层css加载完毕。接下来的gecko应该也是需要等待顶层css加载完毕,否则“css规则树”(见下文)无法建立啊

Gecko渲染

webkit渲染是一个元素与样式规则匹配的过程,Gecko则需要构建样式计算规则书,然后与dom树对应生成样式上下文数(及渲染树)。例子:

<html>
     <body>
          <div class=”err” id=”div1″>
               <p>
                    this is      a <span class=”big”> big error    </span>
                    this is also a <span class=”big”> very big error</span> </p> </div> <div class=”err” id=”div2″> another error </div> </body> </html> //规则 1. div {margin:5px;color:black} 2. .err {color:red} 3. .big {margin-top:3px} 4. div span {margin-bottom:4px} 5. #div1 {color:blue} 6. #div2 {color:green}
样式规则树.png
样式规则树.png

解释一下:A:任意一个父级元素。B、E:代表元素选择器,B指div,E指div下的span。C、G:代表类选择器。D、F:代表:id选择器。后面的123456,代表匹配的规则。

样式上下文树.png
样式上下文树.png

解释一下:当遇到一个dom节点,例如:第二个div,根据css解析结果,进行规则匹配发现符合126这条规则线,我们发现,当遇到第一个div时已经匹配过12这条规则线,所以只需为规则6新增一个节点至样式上下文树的div:F节点。样式上下文树,是元素匹配样式的最终结果(原本是比例的也要换算成具体的px)。 Gecko利用样式规则树,有效的实现了样式共享。Webkit没有规则树,则需要对css解析结果进行多次遍历。出现多次的属性将会被按照正确的级联顺序进行处理最后一个生效。

根据对计算样式困难的理解,我们在编写css样式表时应该注意一下:

  1. dom深度尽量浅。
  2. 减少inline javascript、css的数量。
  3. 使用现代合法的css属性。
  4. 不要为id选择器指定类名或是标签,因为id可以唯一确定一个元素。
  5. 不要给类选择器指定标签,类,代表具有一类属性的标签,不仅是一个,虽然可以实现,但是降低了效率。
  6. 避免后代选择符,尽量使用子选择符。原因:子元素匹配符的概率要大于后代元素匹配符。后代选择符;#tp p{} 子选择符:#tp>p{}
  7. 避免使用通配符,举一个例子,.mod .hd *{font-size:14px;} 根据匹配顺序,将首先匹配通配符,也就是说先匹配出通配符,然后匹配.hd(就是要对dom树上的所有节点进行遍历他的父级元素),然后匹配.mod,这样的性能耗费可想而知.

 

相关文章
|
11月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
268 2
|
7月前
|
数据采集 前端开发 JavaScript
金融数据分析:解析JavaScript渲染的隐藏表格
本文详解了如何使用Python与Selenium结合代理IP技术,从金融网站(如东方财富网)抓取由JavaScript渲染的隐藏表格数据。内容涵盖环境搭建、代理配置、模拟用户行为、数据解析与分析等关键步骤。通过设置Cookie和User-Agent,突破反爬机制;借助Selenium等待页面渲染,精准定位动态数据。同时,提供了常见错误解决方案及延伸练习,帮助读者掌握金融数据采集的核心技能,为投资决策提供支持。注意规避动态加载、代理验证及元素定位等潜在陷阱,确保数据抓取高效稳定。
171 17
|
8月前
|
数据采集 Web App开发 监控
深度解析:使用ChromeDriver和webdriver_manager实现无头浏览器爬虫
在现代网络爬虫实践中,动态网页加载和反爬虫机制增加了数据采集的难度。采用无头浏览器技术(如Selenium与ChromeDriver)可有效模拟用户行为、执行JavaScript,获取动态内容。通过设置代理IP、伪装User-Agent和处理Cookies,提升爬虫隐蔽性和稳定性。该方案适用于电商价格监控、社交媒体数据采集和招聘信息抓取等场景,实现更高效的数据获取。
591 2
深度解析:使用ChromeDriver和webdriver_manager实现无头浏览器爬虫
|
7月前
|
数据采集 消息中间件 JavaScript
浏览器渲染揭秘:从加载到显示的全过程;浏览器工作原理与详细流程
了解浏览器工作原理与流程,能有效帮助前端开发与性能优化。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9月前
|
机器学习/深度学习 自然语言处理 搜索推荐
自注意力机制全解析:从原理到计算细节,一文尽览!
自注意力机制(Self-Attention)最早可追溯至20世纪70年代的神经网络研究,但直到2017年Google Brain团队提出Transformer架构后才广泛应用于深度学习。它通过计算序列内部元素间的相关性,捕捉复杂依赖关系,并支持并行化训练,显著提升了处理长文本和序列数据的能力。相比传统的RNN、LSTM和GRU,自注意力机制在自然语言处理(NLP)、计算机视觉、语音识别及推荐系统等领域展现出卓越性能。其核心步骤包括生成查询(Q)、键(K)和值(V)向量,计算缩放点积注意力得分,应用Softmax归一化,以及加权求和生成输出。自注意力机制提高了模型的表达能力,带来了更精准的服务。
10358 46
|
9月前
|
机器学习/深度学习 人工智能 自然语言处理
深度解析Recraft V3:突破文本渲染限制,文生图黑马是怎样炼成的?
Recraft V3模型在文本生成图像(Text-to-Image)领域取得重大突破,通过创新的&quot;Bridging Text Spotting&quot;方法,解决了传统方法中误差累积和性能不佳的问题。该模型采用独立训练的检测器和识别器,并引入Bridge和Adapter机制,确保高质量图像生成。Recraft V3在多个数据集上表现优异,如Total-Text准确率达83.3%,ICDAR 2015达89.5%。其应用前景广泛,涵盖广告设计、教育和娱乐等领域,为文生图技术的实际应用提供了新可能。
386 27
|
8月前
|
数据采集 Web App开发 存储
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
本文介绍了基于无界面浏览器(如ChromeDriver)和代理IP技术的现代爬虫解决方案,以应对传统爬虫面临的反爬机制和动态加载内容等问题。通过Selenium驱动ChromeDriver,并结合亿牛云爬虫代理、自定义Cookie和User-Agent设置,实现高效的数据采集。代码示例展示了如何配置ChromeDriver、处理代理认证、添加Cookie及捕获异常,确保爬虫稳定运行。性能对比显示,Headless模式下的ChromeDriver在数据采集成功率、响应时间和反爬规避能力上显著优于传统爬虫。该方案广泛应用于电商、金融和新闻媒体等行业。
422 0
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
|
11月前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
11月前
|
缓存 NoSQL Java
千万级电商线上无阻塞双buffer缓冲优化ID生成机制深度解析
【11月更文挑战第30天】在千万级电商系统中,ID生成机制是核心基础设施之一。一个高效、可靠的ID生成系统对于保障系统的稳定性和性能至关重要。本文将深入探讨一种在千万级电商线上广泛应用的ID生成机制——无阻塞双buffer缓冲优化方案。本文从概述、功能点、背景、业务点、底层原理等多个维度进行解析,并通过Java语言实现多个示例,指出各自实践的优缺点。希望给需要的同学提供一些参考。
177 8
|
10月前
|
PHP 开发者 UED
PHP中的异常处理机制解析####
本文深入探讨了PHP中的异常处理机制,通过实例解析try-catch语句的用法,并对比传统错误处理方式,揭示其在提升代码健壮性与可维护性方面的优势。文章还简要介绍了自定义异常类的创建及其应用场景,为开发者提供实用的技术参考。 ####

热门文章

最新文章

推荐镜像

更多
  • DNS