字节面试题:详解浏览器工作原理,CSS全局样式的设置

查找浏览器缓存:浏览器会缓存2-30分钟访问过网站的DNS信息,如未找到 检查系统缓存:检查hosts文件,它保存了一些访问过网站的域名和IP的数据,如未找到 检查路由器缓存:路由器有自己的DNS缓存,如未找到 检查ISP DNS缓存:ISP服务商DNS缓存(本地服务器缓存),如未找到 递归查询:从根域名服务器到顶级域名服务器再到极限域名服务器依次搜索对应目标域名的IP

浏览器与服务器建立TCP连接(3次握手):

第一次握手:客户端向服务器端发送请求等待服务器确认 第二次握手:服务器收到请求并确认,回复一个指令 第三次握手:客户端收到服务器的回复指令并返回确认

请求和传输数据:

服务器解析客户端请求,并返回相应的数据

浏览器渲染页面:

这里先空着,我们下面讲浏览器原理时展开

关闭TCP连接:

当数据完成请求到返回的过程之后,根据Connection的Keep-Alive属性可以选择是否断开TCP连接,四次挥手释放。

Emmmm,到这里这道题目基本解答完毕,但是却引出了另一个问题,浏览器从服务端拿到数据后做了什么才将网页呈现到我们的显示器上,下面就让我们一起来探索浏览器的秘密吧~~

浏览器的高层结构

========

首先让我们看一下浏览器的主要组件:

  • 用户界面:包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面。

  • 浏览器引擎:在用户界面和呈现引擎之间传送指令。

  • 呈现引擎:负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。

  • 网络:用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。

  • 用户界面后端:用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。

  • Javascript解析器:用于解析和执行 JavaScript 代码。

  • 数据存储:这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。

值得注意的是,和大多数浏览器不同,Chrome浏览器的每个标签页都分别对应一个呈现引擎实例。每个标签页都是一个独立的进程。

浏览器的呈现引擎


在浏览器的主要组件中我们最关注的就是浏览器的呈现引擎,因为呈现引擎,顾名思义,它决定了呈现在浏览器的内容。呈现引擎也叫做浏览器内核,不同浏览器使用的呈现引擎是不一样的。常见浏览器使用的呈现引擎如下:

呈现引擎 浏览器 Trident(MSHTML) IE,MaxThon,TT,The World,360,搜狗浏览器等 Gecko Netscape6 及以上版本,FF,MozillaSuite/SeaMonkey 等 Presto Opera7及以上。[Opera内核原为:Presto,现为:Blink] WebkitSafari,Chrome等。[Chrome:Blink(WebKit 的分支)] EdgeHTML Microsoft Edge。[此内核其实是从 MSHTML fork 而来,删掉了几乎所有的 IE私有特性]

下面我们将以Webkit为例讲解浏览器呈现引擎工作的主要流程,Gecko的工作流程与Webkit基本是相同的,只是术语略有不同。

Webkit的主要工作流程


上图展示的是webkit的主要工作流程,接下来我们按照图片的流程来逐渐阐述Webkit是如何工作的。但在这之前我们先要明白从HTTP请求回来开始,呈现引擎的整个工作流程不是一步做完再做下一步,而是一条流水线。

从HTTP请求回来,就产生了流式的数据,后续的DOM树构建、CSS计算、渲染、合成、绘制,都是尽可能地流式处理前一步的产出:即不需要等到上一步骤完全结束,就开始处理上一步的输出,这样我们在浏览网页时,才会看到逐步出现的页面。

HTML解析:从HTML到DOM树

Webkit会用HTML解析算法将HTML转换成DOM树。下面让我们看一下HTML到DOM树的转换:

接下来让我们了解一下HTML解析算法,HTML解析算法的流程如下图所示:

它分为标记化和树构建两个过程:

标记化:

将输入的内容解析成多个标记(HTML标记包括起始标记,结束标记,属性名称,属性值)。标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直至结束。标记化算法是通过状态机实现的。

树构建:

标记生成器发送的每个节点都由树构建器进行处理,规范中定义了每个标记所对应的DOM元素,这些元素会在接收到对应的标记时构建,这些元素不仅会被添加到DOM树,还会添加到开放元素的堆栈中。此堆栈用于纠正嵌套错误和处理未关闭的标记,其算法也可以用状态机来表示。

HTML解析完成后,浏览器会将文档状态标注为交互状态,并开始解析那些处于deferred模式的脚本,然后文档状态设置为完成,一个加载时间将随之触发。

CSS解析:从CSS到StyleSheet对象

CSS解析器会将CSS文件解析成StyleSheet对象,下面让我们来看一下CSS到StyleSheet的转换:

这里我们不讲CSS构建的过程,感兴趣的小伙伴可以看一下参考资料里的重学前端,我们简单的介绍一下CSS选择器的特点,这是由CSS设计原则所决定的。

  • 选择器出现的顺序必定跟构建DOM树的顺序一致,即保证选择器在构建到当前节点时,已经可以准确判断该节点所匹配的CSS规则,不需要后续节点信息。

  • CSS样式匹配时是从右向左匹配的,DOM找到它所有匹配的CSS样式后再做加权计算,确定最终样式,所以也就不难理解chrome操作台内样式表信息为何那样展示了。

构建呈现树:整合DOM树和StyleSheet对象为呈现树

构建呈现树时,需要计算每一个呈现对象的可视化属性。每个DOM节点都有一个"attach"方法,在节点插入DOM树时会调用节点的attach方法,计算该节点的样式属性生成呈现器。下面让我们看一下整合(webkit的术语叫‘附加’)的过程:

排版:将呈现器盒子放到对应的位置

所有的呈现器都有一个“layout”或者“reflow”方法,每一个呈现器都会调用其需要进行布局的子代的layout方法。有很多排版方法:正常流文字排版,绝对定位,浮动元素排版,flex排版等。

渲染:把每一个呈现器对应的盒子变成位图

这里的渲染是借用计算机图形学里面的解释,就是把模型变成位图的过程。

位图就是在内存里建立一张二维表格,把一张图片的每个像素对应的颜色保存进去(位图信息也是DOM树中占据浏览器内存最多的信息,我们在做内存占用优化时,主要就是考虑这一部分)。

合成:合成位图,提升性能

这个过程实际上是一个性能考量,它并非实现浏览器的必要一环。合成的过程就是根据合成策略合并位图。合成策略就是最大限度的减少绘制次数,它是“猜测”可能变化的元素,将它排除到合成之外。

目前,主流浏览器一般根据position、transform等属性来决定合成策略,来“猜测”这些元素未来可能发生变化。但是,这样的猜测准确性有限,所以新的CSS标准中,规定了will-change属性,可以由业务代码来提示浏览器的合成策略,灵活运用这样的特性,可以大大提升合成策略的效果。

绘制:将位图绘制到屏幕上,变成肉眼可见的图像的过程

一般来说,浏览器并不需要用代码来处理这个过程,浏览器只需要把最终要显示的位图交给操作系统即可。

到这里我们已经将Webkit主要的工作流程捋了一遍,现在让我们来总结一下,从HTTP请求回来的数据通过HTML解析器和CSS解析器,分别解析成DOM树和StyleSheet对象,然后整合两者生成呈现树,呈现树调用layout进行排版,然后通过渲染将呈现器盒子变成位图,根据合成策略合成位图提升绘制性能,把位图给操作系统让其绘制到屏幕上。看到这里我们很容易就理解了一个小知识点:CSS不会阻塞DOM的解析,但会阻塞DOM的渲染。

现在我们已经以Webkit为例介绍了呈现引擎的主要工作流程,但是我们似乎还遗漏了些什么。对的,Javascript,我们好像一直没有提及当Webkit解析到JavaScript代码时会怎么处理,接下来就让我们一起来看一看这一部分知识吧~~

浏览器加载JavaScript脚本

=================

正常加载流程

浏览器加载JavaScript脚本,主要通过<script>元素完成。其正常流程如下

浏览器的呈现引擎持有渲染的控制权,它正常解析HTML页面 解析遇到<script>标签,呈现引擎移交控制权给Javascript引擎(例如chrome的V8) 如果<script>标签引用了外部脚本那就先下载再执行,否则直接执行代码 JavaScript引擎执行完毕移交控制权给呈现引擎,呈现引擎继续解析 加载外部脚本时,浏览器会暂停页面渲染,等待脚本下载并执行完成后,再继续渲染。原因是 JavaScript 代码可以修改 DOM,所以必须把控制权让给它,否则会导致复杂的线程竞赛的问题。

defer属性

浏览器解析到包含defer属性的<script>元素时,其运行流程如下

  • 浏览器的呈现引擎持有渲染的控制权,它正常解析HTML页面

  • 解析遇到包含defer属性的<script>标签,继续解析HTML,同时并行下载外链脚本

  • 解析完成,文档处于交互状态时开始解析处于deferred模式的脚本

  • 脚本解析完毕后,将文档状态设置为完成,DOMContentLoaded事件随之触发

使用defer属性时需要注意的点:

  • defer属性下载的脚本文件在DOMContentLoaded事件触发前执行(即刚刚读取完标签)

  • defer属性可以保证执行顺序就是它们在页面上出现的顺序

  • 对于内置而不是加载外部脚本的script标签,以及动态生成的script标签,defer属性不起作用

  • 使用defer加载的外部脚本不应该使用document.write方法

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

技术是没有终点的,也是学不完的,最重要的是活着、不秃。零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。

技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。有需要面试题资料的朋友点击这里可以免费领取


4lCoPEF.jpg" />

最后

技术是没有终点的,也是学不完的,最重要的是活着、不秃。零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。

技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。有需要面试题资料的朋友点击这里可以免费领取

[外链图片转存中…(img-xdmHcs7d-1712333977536)]

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值