深入浏览器原理系列(5):多进程资源加载

前端阳光

共 2906字,需浏览 6分钟

 ·

2021-09-29 16:54

背景知识

Chromium采用多进程架构,本文主要介绍浏览器进程和渲染进程,由于渲染进程是运行在沙盒中,没有直接访问系统资源的能力(如网络资源)。渲染进程中的WebKit/Blink在渲染网页时,首先需要从网络上加载相应的资源文件,比如HTML文档以及文档中的图片、JS脚本、CSS脚本等子资源文件,那么渲染进程就需要先把这些请求通过IPC(进程间通信)的方式发送给浏览器进程,由浏览器进程统一管理和网络数据传输。

这样做有一下几个好处:

  1. 浏览器可以统一管理所有的资源请求;
  2. 浏览器进程可以缓存已经下载完毕的资源文件和Cookie,当有新的请求到达时,如果请求的资源以及存在于缓存中,就直接从缓存中提取,没必须要重新从网络上下载,这样可以节省网络带宽和资源下载的时间。
  3. 自从HTTP/1.1之后,浏览器要求不能为同一域名的主机打开太多的连接,因为如果一个标签页打开太多的Socket链接,可能会导致系统资源消耗过多,这可能会影响到其他标签页或者其他应用程序的运行,这在资源受限的移动平台上显得尤为重要。Chromium目前允许同一主机最多打开6个Socket链接。

总体架构

从上图可知,我们把Chromium资源文件加载的流程大致分为三层,最下面一层是WebKit/Blink层,它运行在渲染进程中的渲染线程中,负责HTML文档的解析、JavaScript/CSS脚本的解析执行和页面的布局等功能;中间一层是渲染进程中与浏览器进程通信的模块,它在渲染进程中的主线程中,负责把WebKit发出的资源请求,转发给浏览器进程;最上面一层就是浏览器进程,它负责控制所有的网络连接和通信,该模块运行在浏览器进程中的IO线程里。

WebKit/Blink

在WebKit/Blink中包括HTML文档在内的所有资源文件都是通过ResourceFetcher类来获取的,现在最新的实现对以前的WebKit资源加载流程做了改进,更多内容请看最后一节“WebKit/Blink如何加载网页资源”。ResourceFethcer类中提供了获取不同资源文件的方法,例如:fetchMainResource方法获取Frame资源,由该方法发送的请求具备最高优先级;fetchImage方法获取图片文件;fetchScript方法获取JavaScript脚本文件资源等等。这些获取资源的方法通过创建和调用ResourceLoader来发送请求。

渲染进程

渲染进程对类ResourceLoaderBridge进行了实现,我们称为IPCResourceLoaderBridge,该类是在content/child/resource_dispatcher.cc中实现的(Chromium后来移动了该文件的位置),该类通过ResourceDispatcher类发送网络资源请求,每个渲染进程中有且之存在一个ResourceDispatcher对象,所有从WebKit发出的网络请求,最后都交给ResourceDispatcher处理,ResourceDispatcher先给每个请求分配一个唯一的ID号,用来区别其他请求,并且组装成一个IPC的信息包ResourceHostMsg_RequestResource,然后把该请求消息交给主线程,由主线程统一与浏览器进程进行IPC。

浏览器进程

浏览器进程中的IO线程的ResourceDispatcherHost会对渲染进程发过来的资源请求消息进行处理,ResourceDispatcherHostImpl::OnRequestResource方法来处理ResourceHostMsg_RequestResource消息,然后把每个消息请求的数据结构变换成chromium中net模块的URLRequest对象,并转发给net模块内部的URLRequestJob类,该对象负责具体网络协议的实现。当URLRequest得到数据或通知时,ResourceDispatcherHost就会收到相应消息,并根据渲染进程中创建的资源请求ID号找到相应的RenderProcessHost,最后把消息发送给渲染进程

Cookies

在Chromium中Cookies存放在浏览器进程中,为所有的渲染进程共享,(手动打开一个新的标签页时使用一个新的渲染进程)。在网页中我们可以通过JavaScritpt脚本document.cookie来访问该网站的cookie值,此时渲染进程需要发送一个同步的IPC给浏览器进程,由于是同步的IPC,所以渲染进程中的渲染线程(WebKit的主循环)就会被阻塞,直到收到浏览器进程的数据返回为止,然后把获取的结果返回给JavaScript引擎,让JavaScript继续执行

WebKit/Blink 如何加载网页资源?

在浏览器渲染网页并呈现给用户之前,首先需要通过网络加载网页资源,这里把资源分成两种,一种是类似Frame的主资源文件,另外一种为类似图片,JavaScript,音频或视频的子资源文件

从WebKit的官方博客上可以得知,WebKit加载这两种资源的方式不同,在代码中采用两种不同的路径来获取资源文件。对于Frame类型的文件,WebKit通过一个DocumentLoader的类来加载。而对于图片,脚本类似的资源文件,WebKit通过一个DocLoader的类来加载,与Frame加载不同的是,DocLoader首先会从缓存中询问是否有资源的备份,如果存在,直接返回备份的资源,这大大减少了文件的下载时间,如果是图片或音视频文件,还可以减少解压时间。如果缓存中不存在文件备份,就新创建一个该文件的备份,为下次加载时使用,这将减少网页重新加载(Reload/Refresh)的时间。

后来Google的工程师对WebKit的这种加载机制做了改进,尽管Frame主资源和图片类的子资源文件有所不同,但是加载的过程实质上类似,所以WebKit/Blink就把两者合并,都采用ResourceFetcher来加载。在网页的加载过程中一般只存在一个ResourceFetcher的实例,当一个网页比较复杂时,需要的加载的资源文件可能会很多,例如网页可能是多个Frame组成的,网页中可能包含图片、JS脚本、CSS脚本、音视频文件和Worker脚本文件等,另外由于网络带宽的影响,资源加载的时间可能会很长,那么如何能快速的让主界面显示给用户来提高用户体验呢(尤其在资源受限的移动设备上)?这里WebKit/Blink对资源文件设定了优先级,把优先级分为五类,即最高优先级,高优先级,中等优先级,低优先级和最低优先级。很明显Frame作为主资源文件享有最高优先级,其他子资源中CSS资源享有高优先级,JS脚本、字体文件被设为中等优先级。


浏览 41
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报