前端小白day2:浏览器是如何运作的

1.浏览器的简单概念

浏览器是运行在操作系统上的一个应用程序。我们知道每个应用程序至少需要一个进程启动来执行其功能。同时,进程会需要执行很多任务,所以进程会创建一些线程来执行这些小的任务。

换句话解释,一个进程就是一辆汽车,要想汽车正常跑起来就需要汽车的各种器件同时运作,而这些器件就是线程。

进程与线程的概念

【进程】 进程是操作系统进行资源分配和调度的基本单元,可以申请和拥有计算机资源,进程是程序的基本单位。

【线程】 线程是操作系统能够进行运算调度的最小单元,一个线程中可以并发多个线程,每条线程并发执行不同的任务。

这样讲可能难以理解,下面会做更加详细的解释。

首先当我们打开一个应用程序时,该应用程序会启动至少一个进程来执行它的任务代码,同时会为该进程分配内存空间。该应用程序的状态信息会保存在所分配的内存空间里,当关闭应用时 ,所分配的内存空间会被回收,这样可以执行更多的进程来完成更多的任务。

由于每个进程分配的内存空间是独立的,如果进程之间需要传递数据,则需要通过IPC管道进行通信,同时,如果一个进程出现问题卡死也不会影响到其他进程。例如汽车的雨刮出现了问题,但是这并不会影响你在晴天继续开车。

进程可以将任务分成更多细小的任务,然后通过创建多个线程并行执行这些细小的任务,统一进程下的线程是可以直接共享数据的。

2.浏览器进程结构

早期的浏览器进程结构

早期的浏览器是单进程模式,其中有页面线程负责渲染和展示,js线程负责执行js代码,还有其他各种线程。但单进程的结构会引发很多问题。

一是不稳定,例如当一个线程卡死可能会导致整个进程出问题;

二是不安全,浏览器之间是可以互相共享数据的,那js线程岂不是可以随意访问浏览器浏览器进程内的所有数据;

三是不流畅,一个进程负责太多事情会导致运行效率的问题。

当今的浏览器进程结构

为了解决以上问题,现在采用多进程浏览器结构,根据进程功能不同来拆分浏览器。

我们可以拆成以下结构:

 【浏览器进程】 浏览器进程负责控制浏览器标签页外的用户界面,包括地址栏,书签,后退,前进等按钮,还进行浏览器其他进程的协调工作。

网络进程】 网络进程负责发起接收网络请求。

GPU进程】 GPU进程负责整个浏览器界面的渲染。

插件进程】 插件进程负责控制网站使用的所有插件。例如flash,注意这里的插件并不是指浏览器扩展里下载的插件。

渲染器进程】 渲染器进程用来控制显示tab标签内的所有内容。

浏览器默认的情况下可能会为每一个标签页都创建一个进程,这个跟选择进程模型有关,感兴趣的可以去了解一下。

3.浏览器的搜索过程

当我们在浏览器地址栏里输入内容时,浏览器内部会发生什么事情呢?

首先,浏览器的UI线程(用户更新UI界面的特殊线程)会捕捉所输入的内容。如果是一个网址,则UI线程会启动一个网络线程来请求DNS进行域名解析,接着开始连接服务器获取数据。如果搜索的是一串内容时,浏览器会启动默认配置的搜索引擎来搜索查询。

 网络线程获取到数据后的操作

当网络线程获取到数据之后会通过站点安全系统(例如谷歌的safeBrowsing)来检查是否是恶意站点,如果是则会弹出警告页面,浏览器会阻止你的访问,当然你也可以强行继续访问。(具体是怎么检查的有兴趣可以去了解一下)

当获取到的数据通过站点安全系统之后,网络线程会通知UI线程已经通过了。然后UI线程会创建一个渲染器进程,浏览器会将数据通过IPC管道传给渲染器进程,然后正式进入渲染流程。渲染器进程所接收到数据就是HTML,渲染器进程负责的核心任务就是把html,css,js,img等资源渲染成用户可交互的web页面。

渲染器进程的主线程会将HTML进行解析,构造DOM数据结构,DOM就是文档对象模型,是浏览器对页面在其内部的表示形式,是web开发程序员可以通过js与之交互的数据结构和API。HTML首先经过Tokerniser标记化,通过词法分析将输入的HTML内容解析成多个标记,根据识别后的标记进行DOM数构造。在DOM数构造的过程中会创建Document对象。然后以Document的为根节点的DOM树不断进行修改,向其中添加各种元素。

HTML代码中往往会引入一些额外资源,比如图片,CSS,js脚本等,图片和CSS这些资源可以通过网络下载,或者从缓存中直接加载,这些资源不会影响HTML的解析,因为他们不会影响DOM的生成。

但当HTML解析过程中遇到script标签,就会停止HTML解析流程。为什么不直接跳过js的加载与执行,要等到html解析完之后再回来加载运行js呢?这是因为浏览器并不知情js是否会改变当前页面的HTML结构,例如,用js执行document.write,那么之前的HTML解析的就可能没有任何意义了。所以我们要把script标签放在合适的位置,又或者使用async或defer属性来异步加载执行js。

 在HTML解析完成之后,我们会获得一个DOM树,但我们还不知道DOM树上的每一个节点应该长什么样子。主线程需要解析CSS,并确定每个DOM节点的计算样式,即使没有提供CSS样式,浏览器也会有自己默认的样式表。

 在知道DOM树和每个节点的样式之后,接下来就需要知道这些节点要放在页面上的哪个位置,也就是节点的坐标以及该节点需要占据做大的区域。以上阶段被称为Layout布局。

主线程通过生成好的DOM树和样式来生成Layout Tree,Layout Tree上的每一个节点都记录了x,y坐标和边框尺寸。这里需要注意的是DOM树和Layout树并不是一一对应的,DOM树是通过HTML解析获得,并不关系到样式,而Layout树是根据DOM树和计算好的样式来生成,Layout树是最终展示在屏幕上的节点是对应的。

 通过以上操作,我们便知道了元素的大小形状和位置,我们还需要知道以什么样的顺序来绘制(paint)节点。为了保证在屏幕上展示正确的层级,主线程遍历Layout树创建一个绘制记录表(Paint Record)。

现在知道了文档的绘制顺序 ,接下来就是要把这些信息转化成像素点显示在屏幕上,而这种行为被称为栅格化(Rastering)。

栅格化的方案

以谷歌举例,早期的Chrome使用了一种很简单的方式,只栅格化用户可视区域内容。当客户移动到其他位置时,再栅格化更多的内容来填充缺失的部分。这种方案会导致显示延迟,所以经过后续的不断优化升级,现在的Chrome使用了更加复杂的栅格化流程——合成(Composting)。

合成是将页面的各个部分分成多个图层,分别对其进行栅格化,并在合成器线程中单独进行合成页面的技术。简单来说就是将各种元素按照某种规则对其进行分图层,然后把图层栅格化,最后把可可视区的内容组合成一帧展示给用户即可。

 回到浏览器怎么将像素点暂时在屏幕上。主线程遍历Layout树生成Layer(图层)Tree,生成完毕和把绘制顺序也确定后,主线程将这些信息传递给合成器线程,合成器线程将每个图层栅格化。

由于一层可能跟页面长度一样大,因此合成器线程会将图层切割成许多图块(tiles),然后将每个图块发送给栅格化线程(Raster Thread)。栅格化线程栅格化每个图块,并将它们存储在DGPU内存中。当图块栅格化完成后,合成器线程将收集称为“draw quads”的图块信息,这些信息记录了图块在内存中的位置,和在页面中的哪个位置绘制图块的信息。

根据这些信息,合成器进程生成了一个合成器帧(Compositor Frame),这个合成器帧通过IPC传送给浏览器进程,接着浏览器进程将合成器帧传送给GPU,然后GPU渲染展示到屏幕上。这时候你就可以看到页面内容。

 当你滚动了页面,这时候合成器进程会生成一个新的合成器帧,然后再通过IPC传给浏览器进程,然后再给GPU渲染到屏幕上。

 当我们改变某个元素的位置属性时,会触发重新布局,重新进行样式计算,布局(Layout)绘制(Paint)以及后面的所有流程,这种行为成为重排。

当我们改变某个元素的颜色属性时,不会重新触发布局,但还是会触发样式计算和绘制,这种行为成为重绘

注意:重排和重绘都会占据主线程。

JS进程的影响

JS进程也会占据主线程,那么就会出现重排、重绘与JS进程抢占执行时间的问题,这样会造成页面卡顿,所以我们写代码时要尽量避免不断重排和重绘。

以上便是全部内容,感兴趣的可以观看以下视频,本文章是根据此视频来制作的,帮助大家更好的理解和掌握知识点。

https://www.bilibili.com/video/BV1x54y1B7RE/?spm_id_from=333.337.search-card.all.click&vd_source=8c7ff41c9353bb0f29cf3a80e7783376

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值