前言
本文主要通过Chrome浏览器来讲解浏览器原理
前置知识
1. CPU
电脑的中央处理器;计算机解析指令以及处理软件中的数据的地方;它会串行的一件一件处理任务;现在所说的多核(4核、8核)是指物理上的核心,表示包含若干个相对独立的CPU核心单元组
2. GPU
GPU是图形处理器;每个GPU核心只能处理简单的任务,但是单片的GPU会有很多个核心,并且可以同时并发的进行工作,所以它有强大的并行计算能力
3. 进程与线程
进程:可以通俗的理解为每个运行的程序都是一个进程
线程:运行在进程里面的,用来执行进程里面的程序代码,一个进程里面会有多个线程
开启一个进程时,操作系统会开辟一个私有的内存空间;这片空间会被用来存储所有该进程相关的数据和状态;只有当进程关闭时,内存空间才会被释放;进程和进程之间是互相独立的,它们互不影响。当一个进程状态异常;不会影响其他进程
Chrome浏览器的多进程架构
这里是从网上找的一张架构图
各个主要进程介绍及职责
Browser Process:浏览器进程,只有一个浏览器进程,负责浏览器的主体部分,包括导航栏、书签、 前进和后退按钮、提供存储等功能
Network Process:网络进程,只有一个网络进程,主要负责页面的网络资源加载(之前是作为一个模块运行在浏览器进程里面的,最近独立出来作为一个单独的进程)
GPU Process:图像渲染进程,只有一个图像渲染进程,负责其它进程的GPU任务。它之所以被独立为一个进程是因为它要处理来自于不同tab的渲染请求并把它在同一个界面上画出来。
Renderer Process:渲染进程,会有多个渲染进程,负责tab内和网页展示相关的所有工作, 比如将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页, 默认情况下每个tab都有一个独立的渲染进程。
UI Process:UI进程,会有多个UI进程,主要负责绘制浏览器顶部按钮和导航栏输入框等组件,当你在导航栏里面输入一个URL的时候,其实就是UI线程在处理你的输入。
Storage Process:存储进程
Plugin Process:插件进程
Extensions Process:扩展程序进程
...
查看Chrome开启的进程
chrome浏览器->更多工具->任务管理器
多进程架构的优点
- 容错性
Chrome会为每个tab单独分配一个属于它们的渲染进程(render process)。当其中一个tab的崩溃时,你可以随时关闭这个tab并且其他tab不受到影响。
- 安全性和沙盒性
因为操作系统可以提供方法让你限制每个进程拥有的能力,所以浏览器可以让某些进程不具备某些特定的功能。例如,由于tab渲染进程可能会处理来自用户的随机输入,所以Chrome限制了它们对系统文件随机读写的能力。
- 每个进程可以拥有更多内存
因为每个进程都会分配一块独立的内存空间, 所以理所当然的, 每个进程都会有更多的内存。
多进程架构的缺点
每个进程都会拥有自己独立的内存空间, 对于一些公共的基础东西如JS引擎,会在多个进程中重复创建浪费内存
Chrome的内存优化
- 限制启动的进程数目,当进程数目达到一定界限后, Chrome会将访问同一个网站的tab都放在一个进程里。
- Chrome服务化, 节省更多的内存 Chrome相关的部分拆分为一个个不同的服务,服务化之后,这些功能既可以放在不同的进程里面运行也可以合并为一个单独的进程运行
这样做的主要原因是让Chrome在不同性能的硬件上有不同的表现。当Chrome运行在一些性能比较好的硬件时,浏览器进程相关的服务会被放在不同的进程运行以提高系统的稳定性。相反如果硬件性能不好,这些服务就会被放在同一个进程里面执行来减少内存的占用。
url导航时都发生了什么
处理输入
由浏览器进程(browser process)里的UI线程(UI thread)进行一系列的解析来判定是将用户输入发送给搜索引擎还是直接请求你输入的站点资源。
开始导航
当输入完成时,UI线程会通知网络进程初始化一个网络请求来获取站点的内容;这时候tab上会显示正在加载中的loading icon(转圈);网络进程会进行DNS地址解析以及为请求建立TLS连接(引用别的大佬介绍文章)的操作。如果网络进程收到服务器的HTTP 301重定向响应,它就会告知UI线程进行重定向然后它会再次发起一个新的网络请求
读取响应
1.响应类型判断
根据HTTP响应主体中Content-Type来判断响应类型;如果缺失Content-Type,浏览器就要进行MIME类型嗅探来确定响应类型了
2.不同响应类型的处理
如果响应的主体是一个HTML文件,浏览器会将获取的响应数据交给渲染进程(renderer process)来进行下一步的工作。 如果拿到的响应数据是一个压缩文件(zip file)或者其他类型的文件,响应数据就会交给下载管理器(download manager)来处理。
3.安全检查
网络进程在把内容交给渲染进程之前还会对内容做SafeBrowsing检查。
如果请求的域名或者响应的内容和某个已知的病毒网站相匹配,网络进程会给用户展示一个警告的页面。除此之外,网络进程还会做CORB(Cross Origin Read Blocking)检查来确定那些敏感的跨站数据不会被发送至渲染进程。
启渲染进程来绘制页面
UI线程在收到网络进程的确认后会为这个网站寻找一个渲染进程(renderer process)来渲染界面。 chrome中在网络进程执行的时候;UI线程会主动地为这个网络请求启动一个渲染线程;如果没有重定向之类的东西出现,网络进程准备好数据后页面的渲染进程已经就准备好了,这就节省了新建渲染进程的时间。
提交导航
数据和渲染进程都已经完成;浏览器进程(browser process)会通过IPC(引用介绍文章)告诉渲染进程去提交本次导航(commit navigation)。 同时浏览器进程还会将刚刚接收到的响应数据流传递给对应的渲染进程。
当浏览器进程收到渲染线程的回复,导航已经被提交了(commit),导航这个过程就结束了,文档的加载阶段(document loading phase)会正式开始。
此时,导航栏会被更新,安全指示符和站点设置会展示新页面相关的站点信息。 当前tab的会话历史(session history)也会被更新,这样当你点击浏览器的前进和后退按钮也可以导航到刚刚导航完的页面。为了方便你在关闭了tab或窗口(window)的时候还可以恢复当前tab和会话(session)内容,当前的会话历史会被保存在磁盘上面。
加载完成
当导航提交完成后,渲染进程开始着手加载资源以及渲染页面。
渲染进程中具体步骤(关键渲染路径)
渲染进程的主要任务是将HTML,CSS,以及JavaScript转变为我们可以进程交互的网页内容。
渲染进程里面有:一个主线程(main thread),几个工作线程(worker threads),一个合成线程(compositor thread)以及一个光栅线程(raster thread)
在渲染进程里面,主线程(main thread)处理了绝大多数你发送给用户的代码。如果你使用了web worker或者service worker,相关的代码将会由工作线程(worker thread)处理。合成(compositor)以及光栅(raster)线程运行在渲染进程里面用来高效流畅地渲染出页面内容。 具体步骤如下
解析
1、构建DOM
渲染进程在导航结束的时候会收到来自浏览器进程提交导航的消息,在这之后渲染进程就会开始接收HTML数据,同时主线程也会开始解析接收到的文本数据,并把它转化为一个DOM(Document Object Model)对象。
2、子资源加载
除了HTML文件,网站通常还会使用到一些诸如图片,CSS样式以及JavaScript脚本等子资源,这些文件会从缓存或者网络上获取。
主线程会按照在构建DOM树时遇到各个资源的循序一个接着一个地发起网络请求,为了提升效率,浏览器会同时运行“预加载扫描”程序。
如果在HTML文档里面存在诸如img或者link这样的标签,预加载扫描程序会在HTML解析器里面找到对应要获取的资源,并把这些要获取的资源告诉浏览器进程里面的网络线程。
3、JavaScript会阻塞HTML的解析过程
当HTML解析器碰到script标签的时候,它会停止HTML文档的解析从而转向JavaScript代码的加载,解析以及执行。
为什么要这样做呢?因为script标签中的JavaScript可能会使用诸如document.write()这样的代码改变文档流(document)的形状,从而使整个DOM树的结构发生根本性的改变。因为这个原因,HTML解析器不得不等JavaScript执行完成之后才能继续对HTML文档流的解析工作。
生成合成树
HTML/CSS/JS 分别解析完成,会生成对应的合成树(attachment)
布局 Layout 生成渲染树
合成树生成之后,需要通过布局(layout)来计算出每个节点的位置信息
布局的具体过程是:
- 主线程遍历生成树,根据节点的计算样式计算出一个布局树(layout tree)。
- 布局树上每个节点会有它在页面上的x,y坐标以及盒子大小(bounding box sizes)的具体信息。
绘制 - Paint
渲染流程图
下图为渲染进程中关键渲染路径流程图
总结
以上就是要讲的所有内容,本文简单介绍了Chrome浏览器的渲染原理流程,感谢阅读!