WebKit之加载模块

转载 2015年11月20日 00:43:51

摘要:本文介绍 WebCore  Loader 模块是如何加载资源的,分主资源和派生资源分析loader 模块的类关系。

关键词: WebKit,Loader,Network,ResouceLoader,SubresourceLoader

一、类结构及接口

Loader 模块是 Network 模块的客户。 Network 模块提供指定资源的获取和上传功能,获取的资源可能来自网络、本地文件或者缓存。对不同 HTTP 实现的适配会在Network 层完成,所以 Loader 接触到的基本上是同 OS  HTTP 实现无关的 Network 层接口。

 


 

如上是 Loader  NetWork 之间的类关系图, ResourceHandleClient ResourceHandle 的客户,它定义一系列虚函数,这些虚函数是 ResouceHandle 的回调,继承类实现这些接口。

ResouceHandleClient 的接口同网络传输过程息息相关,一般为某一个网络事件对应的回调。下面是其中的一些接口。

// 一般情况下,在发起网络请求前调用,可以设置特定的 Http

头部,比如 user agent 等,在重定向请求的时候,也会自动调

void willSendRequest(ResourceHandle*, ResourceRequest&, const

ResourceResponse&)

// 上传数据的时候,在 TCP wrtie 事件的时候,向对方发送数据的

时候调用, loader 可以根据这个回调显示上传进度。

void didSendData(ResourceHandle*, unsigned long long

/*bytesSent*/, unsigned long long /*totalBytesToBeSent*/)

// 收到第一个响应包,此时至少 http 的部分头部已经解析(如

status code ), loader 根据响应的头部信息判断请求是否成功

等。

void didReceiveResponse(ResourceHandle*,

const   ResourceResponse&)

// 收到 HTTP 响应数据,类似 tcp  read 事件,来 http 响应数据

了, Network 的设计机制是来一段数据上传一段数据。

void didReceiveData(ResourceHandle*, const char*, int,

  int /*lengthReceived*/)

    // 加载完成,数据来齐。

void didFinishLoading(ResourceHandle*, double /*finishTime*/)

// 加载失败

void didFail(ResourceHandle*, const ResourceError&)

// 要求用户鉴权

void didReceiveAuthenticationChallenge(ResourceHandle*,

const AuthenticationChallenge&)

WebCore 把要加载的资源分成两类,一类是主资源,比如 HTML 页面,或者下载项,一类是派生资源,比如 HTML 页面中内嵌的图片或者脚本链接。这两类资源对于回调的处理有很大的不同,比如,同样是下载失败,主资源可能需要向用户报错,派生资源比如页面中的一张图下载失败,可能就是图不显示或者显示代替说明文字而已,不向用户报错。因此有了 MainResourceLoader  SubresourceLoader 之分。它们的公共基类 ResourceLoader 则完成一些两种资源下载都需要完成的操作,比如通过回调将加载进程告知上层应用。

ResourceLoader 通过 ResourceNotifier 类将回调传导到 FrameLoaderClient 类。


        

主资源的加载是立刻发起的,而派生资源则可能会为了优化网络,在队列中等待 (这里的立刻发起是 loader 层面的,不是 Network 层面的 )  ResourceScheduler 这个类就是用来管理资源加载的调度。主要调度对象就是派生资源,会根据 host 来影响资源加载的先后顺序。

主资源和派生资源的加载还有一个区别,主资源目前是没有缓存的,而派生资源是有缓存机制的。这里的缓存指的是 Resouce Cache ,用于保存原始数据(比如 CSS JS 等),以及解码过的图片数据,通过 Resource Cache 可以节省网络请求和图片解码的时候。不同于 Page Cache  Page Cache 存的是 DOM 树和 Render 树的数据结构,用来在前进后退的时候快速显示页面。

二、加载流程

    下图是加载 html 页面时,一个正常的加载流程。

 

三、主资源加载过程

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 解析

23.   数据来齐,调用 MainResourceLoader::didFinishLoading

24.   调用 FrameLoader::finishedLoading

25.   调用 DocumentLoader::finishedLoading

26.   调用 FrameLoader::finishedLoadingDocument ,启动 writer 对象接收剩余数据,重复 19-22 进行解析

27.   调用 DocumentWriter::end 结束接收数据(调用 Document::finishParsing 

28.   调用 HTMLDocumentParser::finish

四、派生资源加载流程

  在派生资源的加载中, SubresourceLoader 更多起到的是一个转发的作用,通过它的 client  SubresourceLoaderClient 类)来完成操作。


 

 

   各个加载阶段的处理在 SubresourceLoaderClient 的派生类CachedResourceRequest,Loader,IconLoader 中完成。 Client 会创建 SubresourceLoader 

请求发起阶段, ResourceLoadScheduler 负责对 SubresourceLoader 进行调度。


   Document 类会创建 CachedResourceLoader 类的对象 m_cachedResourceLoader, 这个类 ( 对象 ) 提供了对 Document 的派生资源的访问接口 requestImage requestCSSStyleSheet  requestUserCSSStyleSheet  requestScript  requestFont requestXSLStyleSheet  requestLinkPrefetch 。为了实现这些接口,CachedResourceLoader 需要创建 CachedResourceRequest 对象来发起请求。

一般情况下,一个 Document 拥有一个 CachedResourceLoader 类实例。

MemoryCache 类则对提供缓存条目的管理,可以方便地进行 add  remove ,缓存淘汰等。具体的缓存条目则是通过 CachedResource 类存储, MemoryCache 类维护了一个 HashMap 存储所有缓存条目。

HashMap <String,CachedResource> m_resources;

CachedResourceRequest 依赖于 CachedResource,  CacheResourceRequest 的构造函数中,会传入 CachedResource 对象作为参数。 CachedResource 既存储响应体部,也存储同 cache 相关的头部。在发起请求前,会检查是否有 cache  validator ,在收到响应的时候,则需要更新对应的头部。 CachedResource 类实现了 RFC2616 中的缓存一节。实际上 CachedResource 类真正完成了同网络的通信。 CachedResource 类根据申请的资源类型派生出不同的子类。



      CachedResource 类的使用者必须是 CachedResourceClient, 在这个类中维护了CachedResourceClient 类的集合 m_clients 。每一个 Client 通过 addClient  removeClient将自己加入到该类的 Client 集合中。 CachedResourceClientWalker 则提供了CachedResouceClient 的一个遍历接口。当数据来齐的时候, CachedResource 类会通过CachedResouceClient::notifyFinished 接口通知使用者。

下图是 Image 元素对应的几个类关系。



 

下面以 image 为例分析其加载过程

1.        解析 html 页面的时候,解析到 img 标签,调用 HTMLImageElement::create 创建 HTMLImageElement 对象,该对象包含 HTMLImageLoader 对象m_imageLoader

2.        解析到 img  href 属性,调用ImageLoader::updateFromElementIgnoringPreviousError

3.        调用 ImageLoader::updateFromElement

4.        调用 CachedResourceLoader::requestImage

5.        调用 CachedResourceLoader::requestResource( 根据缓存的情况确定是否可以从缓存获取,或者需要 revalidate ,或者需要直接从网络获取 )

6.        调用 CachedResourceLoader::loadResource

7.        根据 Resource 的类型调用 createResource 创建对应的 CachedResource

8.        调用 MemoryCache::add  cache 中查找是否有对应的 cache 条目,如果没有创建之

9.        调用 CachedImage::load

10.   调用 CachedResource::load

11.   调用 CachedResourceLoader::load

12.   调用 CachedResourceRequest::load

13.   创建 CachedResourceRequest 对象,它将作为 SubresourceLoader  client

14.   调用 ResourceLoaderScheduler::scheduleSubresourceLoad

15.   调用 SubresourceLoader::create

16.   ResourceLoadScheduler::requestTimerFired

17.   调用 ResourceLoader::start

18.   调用 ResourceHandle::create 发起请求

19.   收到 HTTP 响应头部,调用 ResourceLoader::didReceiveResponse

20.   调用 SubresourceLoader::didiReceiveResponse

21.   调用 CachedResourceRequest::didReceiveResponse 处理响应头部,特别是同缓存相关的头部,比如 304  status code

22.   调用 ResourceLoader::didReceiveResponse

23.   收到体部数据,调用 ResourceLoader::didReceiveData

24.   调用 SubresourceLoader::didReceiveData

25.   调用 ResourceLoader::didReceiveData

26.   调用 ResourceLoader::addData 将数据存储到 SharedBuffer 里面

27.   调用 CachedResourceRequest::didReceiveData

28.   数据来齐 , 调用 ResourceLoader::didFinishLoading

29.   调用 SubresourceLoader::didFinishLoading

30.   调用 CachedResourceRequest::didFinishLoading

31.   调用 CachedResource::finish

32.   调用 CachedResourceLoader::loadDone

33.   调用 CachedImage::data ,创建对应的 Image 对象,解码

相关文章推荐

Webkit加载模块

1,Webkit加载的主要模块 Loader的主要模块包括Frameloader、DocumentLoader以及MainResourceLoader,加载的命令是Frame传进来的。加载主要涉及的...

Android WebKit HTML主资源加载过程

  • 2016年04月06日 16:58
  • 33KB
  • 下载

Webkit初始化以及加载URL过程中各种对象的建立时序以及DOM树的建立详情分析

众所周知,Webkit需要创建DOM树。为此它需要创建WebView, Chrome,Page,Frame, Document, Document Parser, DOM Tree Builder(D...

WebKit加载网页流程

在WebKit渲染一个页面之前,它需要从网络上(其实也可以从本地文件或者内存加载)加载页面以及和它相关的所有派生资源。同加载资源相关的层有很多,在本文中,我将聚焦于解释WebCore,这一WebKit...
  • rgxgf
  • rgxgf
  • 2011年11月11日 09:33
  • 1105

Webkit学习 ----网页资源的构建加载流程

Webkit的作用在这就不多做介绍了,本篇主要还是个人在源码分析了webkit之后的心得总结!       webkit有上千个类,在这么错综复杂的结构里看流程无疑找死,好吧,用GDB调试看吧!...

在浏览器内核WebKit中并行加载外部脚本

在WebKit内核的浏览器中,通过设定HTML5中async 和 defer 属性,并行下载脚本。

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

在浏览器渲染网页并呈现给用户之前,首先需要通过网络加载网页资源,这里把资源分成两种,一种是类似Frame的主资源文件,另外一种为类似图片,JavaScript,音频或视频的子资源文件。 从WebKit...
  • yl02520
  • yl02520
  • 2014年02月21日 11:28
  • 2229

webkit加载adobe flash player 10.1[转自邓大侠]

这个不是文档,这个是个人臆测。Webkit插件加载路径代码在external/webkit/webcore/plugins/PluginDatabase.cpp中。代码为:Vector PluginD...

WebKit加载网页的流程

摘要:WebKit源码分析,WebKit文档,WebCore,loader,ResourceLoader,MainResourceLoader,SubresourceLoader,DocumentLo...

Webkit页面加载过程分析(1)-发送请求篇

在WebKit渲染页面前,首先要从网络加载主页面和所有的子资源数据,本文描述主页面资源加载过程中Get请求发送过程。 分析的源码基于Qt5beta2版本的WebKit   图1 WebC...
  • sgiwxyg
  • sgiwxyg
  • 2012年12月06日 00:52
  • 1331
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WebKit之加载模块
举报原因:
原因补充:

(最多只允许输入30个字)