Webkit主资源加载流程(推荐)

15 篇文章 0 订阅

【参考地址】http://blog.csdn.net/luoxinwu123/article/details/8204824

【参考地址】http://www.cnblogs.com/lfsblack/p/5342631.html

1,Webkit加载的主要模块

Loader的主要模块包括FrameloaderDocumentLoader以及MainResourceLoader,加载的命令是Frame传进来的。加载主要涉及的Webkit模块是pageloaderplatform。主要模块图如下:


图1:加载模块图

2,主要类结构

在加载模块中,PageFrame是最主要的与客户代码打交道的类。Page类与各种Client通信,如ContextMenuClientEditorClient等,从而为一个Page负责菜单以及输入等事件的处理。一个Page中可能含有多个Frame,但只有一个主FramePage本身的功能很少,基本上是组合其他对象,把功能委托到其他对象上。


FrameTree对象用来协助管理父帧和子帧的关系。
NavigationScheduler对象用来管理页面跳转调度(比如重定向,meta refresh等)。
DOMWindow用来管理同DOM相关的事件、属性和消息。
FrameView用于Frame的排版。
Document用于管理DOM节点。
EventHandle是事件的处理对象,主要是同上层应用也就是用户参与的事件的处理。
一个Frame包含一个FrameLoader作为加载的最主要的负责对象。


图3:FrameLoader的类结构


FrameLoader中最重要的类是DocumentLoader,负责页面的加载。FrameLoader维护了三个DocumentLoader对象,分别对应于不同的阶段,m_policyDocumentLoader对应于收到用户load调用,进行policy check阶段,m_provisionalDocumentLoader对应于policy check通过以后,Frame数据还没有到来之前,它会负责startLoadingMainResource的调用。m_documentLoader则是Frame第一个数据到来以后使用的DocumentLoader,这个时候,前一个主Frame的DocumentLoader已经不能再用(user agent开始白屏,刷掉前一个页面的显示)。
SubFrameLoader负责子Frame的加载
DocumentWriter负责加载结束之后的数据处理


FrameLoaderStateMachine维护FrameLoader的状态
PolicyChecker主要用来对FrameLoader进行一些校验
ResourceLoadNotifier主要用于同ResourceLoader及FrameLoaderClient打交道(可以理解为 ResourceLoader有事件变化或者发生的时候,通知FrameLoader的一个手段)
3, 加载中的网络模块
Webkit封装了一个NetWork与Load模块交互,Network模块一方面提供与操作系统和网络实现无关的接口与Load通信,另一方面通过具体实现则委托给具体的操作系统和网络实现。


图4:Network与Load的交互图

如图所示,ResourceHandle是Network模块的核心类,它提供网络操作的接口,具体实现则由其子类根据不同的平台来实现。ResourceHandle与ResourceHandleClient之间的实现采用了桥接模式(将抽象部分与实现部分分离,使它们都可以独立的变化 )。
另外,Network 的设计机制是接收一段数据,就把这段数据传给Load模块,然后Load模块再将数据提交给解析模块。

ResourceHandleClient 是ResourceHandle 的客户,它定义一系列虚函数,这些虚函数是 ResouceHandle 的回调,继承类实现这些接口,ResourceHandleClient更多的继承关系如下图:


ResouceHandleClient 的接口同网络传输过程息息相关,一般为某一个网络事件对应的回调。下面是其中的一些接口
一般情况下,在发起网络请求前调用,可以设置特定的 Http头部,比如 user agent 等,在重定向请求的时候,也会自动调用

virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) { }
上传数据的时候,在 TCP wrtie 事件的时候,向对方发送数据的时候调用, loader 可以根据这个回调显示上传进度。
virtual void didSendData(ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { }
收到第一个响应包,此时至少 http 的部分头部已经解析(如status code ), loader 根据响应的头部信息判断请求是否成功等
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) { }
收到 HTTP 响应数据,类似 tcp 的 read 事件,来 http 响应数据了, Network 的设计机制是来一段数据上传一段数据
virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/) { }
加载完成,数据来齐
virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) { }
加载失败
virtual void didFail(ResourceHandle*, const ResourceError&) { }
要求用户鉴权
virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { }
WebCore 把要加载的资源分成两类,一类是主资源,比如 HTML 页面,或者下载项,一类是派生资源,比如 HTML 页面中内嵌的图片或者脚本链接。这两类资源对于回调的处理有很大的不同,比如,同样是下载失败,主资源可能需要向用户报错,派生资源比如页面中的一张图下载失败,可能就是图不显示或者显示代替说明文字而已,不向用户报错。因此有了 MainResourceLoader 和 SubresourceLoader 之分。它们的公共基类 ResourceLoader 则完成一些两种资源下载都需要完成的操作,比如通过回调将加载进程告知上层应用
ResourceLoader 通过 ResourceNotifier 类将回调传导到 FrameLoaderClient 类。
4,加载过程
以Qt为例,主要过程如下:


图5: 加载过程图
如图可知,在Qt中,加载是从QWebView的load()开始,先获取QWebPage,通过QWebPage得到QWebFrame,然后调用QWebFrame的load()函数,去到Webkit的内核Frame的loader(),从而得到FrameLoader实例。Frameloader会把加载的工作交给DocumentLoader。


5,,加载细节
WebCore 把要加载的资源分成两类,一类是主资源,比如 HTML页面,或者下载项,一类是派生资源,比如 HTML 页面中内嵌的图片或者脚本链接。这两类资源对于回调的处理有很大的不同,比如,同样是下载失败,主资源可能需要向用户报错,派生资源比如页面中的一张图下载失败,可能就是图不显示或者显示代替说明文字而已,不向用户报错。因此有了 MainResourceLoader 和 SubresourceLoader 之分。它们的公共基类 ResourceLoader 则完成一些两种资源下载都需要完成的操作,比如通过回调将加载进程告知上层应用。
ResourceLoader 是通过 ResourceNotifier 类将回调传导到 FrameLoaderClient 类。不同的平台或框架会有一个类来继承该类,从而把加载的相关操作通知到上层应用,上层应用接收到通知之后会做出相应的响应。在Qt中,这个类是FrameLoaderClientQt,它会将相关通知发送给QWebFrame。
我们以主资源加载为例,描述整个加载过程的细节。
DocumentLoader在startLoadingMainResource中调用 MainResourceLoader::load 向 loader 发起请求。在MainResourceLoader::load中调用MainResourceLoader::loadNow,loadNow中先调用willSendRequest。在willSendRequest中,会首先调用其父类ResourceLoader的willSendRequest,将callback 通过 ResourceNotifier传给 FrameLoaderClient 。Client可以在回调中操作 ResourceRequest,如设置请求头部。接着会做一个PolicyCheck的动作,既调用 PolicyChecker::checkNavigationPolicy 过滤掉重复请求等。这些完成之后,在loadNow中调用 ResourceHandle::create 向 Network 发起加载请求。
网络请求发出之后,网络模块会收到应答,既第一个HTTP响应数据包。这时候网络模块的ThreadableLoaderClient回调MainResourceLoader::didReceiveResponse来处理HTTP头部。在didReceiveResponse继续调用 PolicyChecker:: checkContentPolicy, 并最终通过 FrameLoaderClient 的dispatchDecidePolicyForMIMEType 判断是否为下载请求(存在 "Content-Disposition"http 头部)。再继续调用调用 MainResourceLoader::continueAfterContentPolicy ,根据ResourceResponse 检测是否发生错误。再调用 ResourceLoader::didReceiveResponse ,将 callback 通过 ResourceNotifier传导给 FrameLoaderClient。
当收到HTTP Body数据后,网络模块的SocketStreamHandle会调用 MainResourceLoader::didReceiveData,在这个函数中会去调用其父类 ResourceLoader的didReceiveData。在ResourceLoader::didReceiveData中调用addData(),这个会调用 MainResourceLoader::addData。在MainResourceLoader::addData中会通过FrameLoader::receivedData来调用DocumentLoader::receivedData,并通过该函数进入DocumentLoader::commitLoad。这一步中,会先调用commitIfReady(),并通过
FrameLoader::commitProvisionalLoad,使FrameLoader从provisional 状态跃迁到 Committed 状态;然后通过调用FrameLoader::committedLoad进入FrameLoaderClientQt::committedLoad。再调用 DocumentLoader::commitData ,启动 Writer 对象来处理数据(使用DocumentWriter::setEncoding , DocumentWriter::addData)。进入 DocumentParser::appendByte,再进入DecodedDataDocumentParser::appendBytes 对文本编码进行解码,然后通过HTMLDocumentParser::append,进行HTML解析。
当数据接收完之后,会调用 MainResourceLoader::didFinishLoading。这一步中,会先通过FrameLoader::finishedLoading进入DocumentLoader::finishedLoading,然后做一些资源释放的动作。整个主资源加载过程节结束了。


总结下主要流程:
1.        DocumentLoader 调用 MainResourceLoader::load 向 loader 发起请求
2.        调用 MainResourceLoader::loadNow
3.        调用 MainResourceLoader::willSendRequest
4.        调用 ResourceLoader::willSendRequest, 将 callback 通过 ResourceNotifier 传导给 FrameLoaderClient 。 Client 可以在回调中操作 ResourceRequest ,比如设置请求头部。
5.        调用 PolicyChecker::checkNavigationPolicy 过滤掉重复请求等
6.        loader 调用 ResourceHandle::create 向 Network 发起加载请求
7.        收到第一个 HTTP 响应数据包 ,Network 回调MainResourceLoader::didReceiveResponse ,主要处理 HTTP 头部。
8.        调用 PolicyChecker:: checkContentPolicy, 并最终通过 FrameLoaderClient 的dispatchDecidePolicyForMIMEType 判断是否为下载请求(存在 "Content-Disposition"http 头部)
9.        调用 MainResourceLoader::continueAfterContentPolicy ,根据ResourceResponse 检测是否发生错误。
10.   调用 ResourceLoader::didReceiveResponse ,将 callback 通过 ResourceNotifier传导给 FrameLoaderClient 。
11.   收到 HTTP 体部数据,调用 MainResourceLoader::didReceiveData
12.   调用 ResourceLoader::didReceiveData ,将 callback 通过 ResourceNotifier 传导给 FrameLoaderClient
13.   调用 MainResourceLoader::addData
14.   调用 DocumentLoader::receivedData
15.   调用 DocumentLoader::commitLoad
16.   调用 FrameLoader::commitProvisionalLoad , FrameLoader 从 provisional 状态跃迁到 Committed 状态
17.   调用 FrameLoaderClientQt::committedLoad
18.   调用 DocumentLoader::commitData ,启动 Writer 对象来处理数据(DocumentWriter::setEncoding , DocumentWriter::addData )
19.   调用 DocumentWriter::addData
20.   调用 DocumentParser::appendByte
21.   调用 DecodedDataDocumentParser::appendBytes 对文本编码进行解码
22.   调用 HTMLDocumentParser::append ,进行 HTML 解析


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值