4.1 Loader概述
我们使用浏览器上网时,首先会在地址栏输入一个网址,浏览器会依据网址向服务器发送资源请求,服务器解析请求,并将相关数据资源传回给浏览器,这些数据资源包括Page的描述文档、图片、Javascript脚本、CSS等。此后,浏览器引擎会对数据进行解码、解析、排版、绘制等操作,最终呈现出完整的页面。
在过去,Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本、样式表链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。这两类资源的加载过程颇有不同,比如对资源加载失败的处理,主资源下载失败会有报错提示,而派生资源如图片下载失败,往往只显示一个占位符。所以网络加载模块分别设计了MainResourceLoader和SubresourceLoader来处理它们。它们的公共基类ResourceLoader主要完成两种资源加载都需要进行的操作,如在资源加载过程中,反馈加载状态的回调等。
注:自从WebKit有了PageCache(主资源也可以缓存)的功能以后。WebKit资源加载已经不区分MainResourceLoader和SubresourceLoader,统一由CachedResourceLoader加载资源,而区分主资源和派生资源则是通过CachedResource类里面Type类型:
enum Type {
MainResource,
ImageResource,
CSSStyleSheet,
Script,
FontResource,
RawResource
};
可以看到加载主资源的时候,Type类型就为MainResource。由于目前我们使用的WebKit代码已经使用了比较新的代码,所以本章后面介绍的流程都与过去的流程不一样了。
4.2 Loader中的类结构以及作用
为了梳理出Loader模块中相关类之间的关系!在阅读源码时,可参考这张图,有助于加深对Loader整体的理解。
FrameLoader类提供了资源加载的一系列接口,因此与FrameLoader交互的类比较多,以下是FrameLoader类与其他比较重要类的内在关系图:
首先简要说明图中几个类的作用。
FrameLoaderClient:是FrameLoader的客户接口类,在不同的平台实现也不相同,比如在Qt平台、Android平台、Gtk平台等。FrameLoader将加载过程中的状态、结果等信息传递给FrameLoaderClient,FrameLoaderClient可以管控FrameLoader的动作。
HistoryController:处理历史记录相关的接口,保存或者恢复Page和Document的状态到HistoryItem,维护浏览器页面的前进后退队列,以实现前进后退功能。
PolicyChecker:对FrameLoader进行一些校验。包括三种校验:NewWindowPolicy、NavigationPolicy、ContentPolicy。NewWindowPolicy对应于浏览器需要新开一个tab页或者窗口时。NavigationPolicy对应于一个页面请求发起时。ContentPolicy校验对应于收到数据以后(如判断MimeType等)。PolicyChecker提供对应的接口,由FrameLoaderClient来对这些请求进行校验,以确定是否允许继续加载或者需要执行其他的动作。
ResourceLoadNotifier:用于与ResourceLoader和FrameLoaderClient通信。在资源加载过程中,将ResourceLoader的状态通过ResourceLoadNotifier通知给FrameLoaderClient。
SubFrameLoader:用于控制MainFrame的子Frame(如iframe)的加载。
DocumentLoader:FrameLoader包含了三个DocumentLoader对象,在资源加载的不同阶段被使用,其中m_policyDocumentLoader应用在Load请求产生时的Policy Check阶段。m_provisionalDocumentLoader应用在Policy Check通过后,发起网络请求的阶段。m_documentLoader则是收到Server发回的资源数据包后使用的DocumentLoader。不过在实际的资源加载过程中,三个DocumentLoader对应于同一个对象。
FrameLoaderStateMachine:通过FrameLoaderStateMachine来反映FrameLoader的状态,描述DocumentLoader的状态。
4.3 资源加载流程
正如概述所说,比较新的WebKit代码主资源已经加入了缓存机制,所以统一由CachedResourceLoader加载资源,以下加载主资源的时序图:
WebKit派生资源包含的类型主要如下:
Javascript脚本(CachedScript);
CSS样式文本(CachedCSSStyleSheet);
图片(CachedImage);
字体(CachedFont);
XSL样式表(CachedXSLStyleSheet);
可以说除了主资源剩下的网络资源都是派生资源。派生资源的WebKit中都有对应的类实现,它们有着共同的基类(CachedResource),下面是类图:
WebKit在加载主资源后,主资源会被解码,然后进行解析,生成DOM树。在解析的过程中,如果遇到派生资源的标签,会创建相应的HTMLElement类。我们以image(会创建HTMLImageElement类)为例,时序图如下:
4.4 本章小结
本章主要介绍了Loader模块的设计与实现,包括Loader的相关类介绍。对比主资源和派生资源加载流程,大家会发现很多相似之处。Loader模块较为复杂但非常重要,希望本章能给大家一些帮助。