浏览器原理笔记
浏览器工作原理
浏览器架构
- 单进程,多线程
- 多进程,多线程,进程间通过IPC(Inter Process Communication)通信
谷歌多进程架构
各进程的分工
- 浏览器进程
UI线程,网络线程,存储线程...
负责浏览器的“Chrome”部分, 包括导航栏,书签, 前进和后退按钮。同时这个进程还会控制那些我们看不见的部分,包括网络请求的发送以及文件的读写。 - 渲染进程
主线程,几个工作线程,合成线程,光栅线程
负责标签页内和网页展示相关的所有工作 - 插件进程
控制网页使用的所有插件,例如flash插件。 - GPU进程
负责独立于其它进程的GPU任务。它之所以被独立为一个进程是因为它要处理来自于不同tab的渲染请求并把它在同一个界面上画出来。 - 扩展进程
- 工具进程
- 通过浏览器的任务管理器查看所有进程
多进程的优缺点
- 容错性高,不同的tab会有不同的渲染进程来负责,所以一个标签页的渲染进程崩溃,其他页面不受影响.
- Chrome采用多进程架构的另外一个好处就是可以提供安全性和沙盒性(sanboxing)。因为操作系统可以提供方法让你限制每个进程拥有的能力,所以浏览器可以让某些进程不具备某些特定的功能。例如,由于tab渲染进程可能会处理来自用户的随机输入,所以Chrome限制了它们对系统文件随机读写的能力
- 进程开多了耗内存,所以为了节省内存,Chrome会限制被启动的进程数目,当进程数达到一定的界限后,Chrome会将访问同一个网站的tab都放在一个进程里面跑。
Chrome的服务化
- Chrome浏览器的架构正在发生一些改变,目的是将和浏览器本身(Chrome)相关的部分拆分为一个个不同的服务,服务化之后,这些功能既可以放在不同的进程里面运行也可以合并为一个单独的进程运行。
单帧渲染进程 - 网站隔离
- 网站隔离(Site Isolation)是最近Chrome浏览器启动的功能,这个功能会为网站内不同站点的iframe分配一个独立的渲染进程。之前说过Chrome会为每个tab分配一个单独的渲染进程,可是如果一个tab只有一个进程的话不同站点的iframe都会跑在这个进程里面,这也意味着它们会共享内存,这就有可能会破坏同源策略。同源策略是浏览器最核心的安全模型,它可以禁止网站在未经同意的情况下去获取另外一个站点的数据,因此绕过同源策略是很多安全攻击的主要目的。而进程隔离(proces isolation)是隔离网站最好最有效的办法了。
从导航(navigation)开始
- 浏览器中tab外面发生的一切都是由浏览器进程(browser process)控制的。浏览器进程有很多负责不同工作的线程(worker thread),其中包括绘制浏览器顶部按钮和导航栏输入框等组件的UI线程(UI thread)、管理网络请求的网络线程(network thread)、以及控制文件读写的存储线程(storage thread)等。当你在导航栏里面输入一个URL的时候,其实就是UI线程在处理你的输入。
- UI线程处理输入
- UI线程让网络线程请求网络
- 网络线程读取响应
- 寻找一个渲染进程
- 渲染进程提交(commit)导航
- 文档加载阶段开始
读取响应阶段
- 网络线程在收到HTTP响应的主体(payload)流(stream)时,在必要的情况下它会先检查一下流的前几个字节以确定响应主体的具体媒体类型(MIME Type)。
- 如果响应的主体是一个HTML文件,浏览器会将获取的响应数据交给渲染进程(renderer process)来进行下一步的工作。如果拿到的响应数据是一个压缩文件(zip file)或者其他类型的文件,响应数据就会交给下载管理器(download manager)来处理。
- 网络线程在把内容交给渲染进程之前还会对内容做SafeBrowsing检查。如果请求的域名或者响应的内容和某个已知的病毒网站相匹配,网络线程会给用户展示一个警告的页面。除此之外,网络线程还会做CORB(Cross Origin Read Blocking)检查来确定那些敏感的跨站数据不会被发送至渲染进程。
...
渲染阶段
将html解析为dom过程
-
创建document对象,解析html,将元素对象和文本内容添加到文档中,此时document.readyState = 'loading'
-
遇到link外部css的时候,创建新的线程异步加载,继续解析html
-
遇到有src的scripts(没有async和defer标记)加载外部的js时,同步加载并阻塞解析html,而且加载完马上执行
-
遇到设置async和defer的script,创建新的线程异步加载,继续解析html。async加载完马上执行,defer在DOMContentLoaded前执行
-
遇到带有src的img,解析dom结构,再异步加载src的图片资源,不会等待img加载完成继续解析文档。另外,img要等待css加载完才解码,所以css阻塞图片的呈现,类似于js阻塞html解析一样。可以想一下,如果css被设置为display:none,还有意义吗?所以此时虽然对后台有请求但不解码
-
文档解析完毕,document.readyState = 'interactive'
-
此时带有defer的js开始按顺序执行
-
DOMContentLoaded触发,程序从同步脚本执行转化为事件驱动阶段(类似ele.onclick = handel已经开始生效)
-
当所有的script加载完成并且成功执行、img和css加载完毕,document.readyState = 'completed',触发onload事件
-
异步响应ui行为,开始交互
将CSSOM和DOM合并成渲染树
因为浏览器有GUI渲染线程与JS引擎线程,为了防止渲染出现不可预期的结果,这两个线程是互斥的关系。
JavaScript的加载、解析与执行会阻塞DOM的构建
,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。
JS文件不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建。
浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。
布局与绘制
通过构造渲染树,我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。
回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。
回流一定会触发重绘,而重绘不一定会回流
浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制。
CSSOM会阻塞渲染,只有当CSSOM构建完毕后才会进入下一个阶段构建渲染树。
通常情况下DOM和CSSOM是并行构建的,但是当浏览器遇到一个不带defer或async属性的script标签时,DOM构建将暂停,如果此时又恰巧浏览器尚未完成CSSOM的下载和构建,由于JavaScript可以修改CSSOM,所以需要等CSSOM构建完毕后再执行JS,最后才重新DOM构建。