webkit內核源碼分析四

摘要:本文介紹 WebCore  Loader 模塊是如何加載資源的,分主資源和派生資源分析 loader 模塊的類關係。

關鍵詞: WebKit,Loader,Network,ResouceLoader,SubresourceLoader

一、類結構及接口

Loader 模塊是 Network 模塊的客戶。 Network 模塊提供指定資源的獲取和上傳功能,獲取的資源可能來自網絡、本地文件或者緩存。對不同 HTTP 實現的適配會在 Network 層完成,所以 Loader 接觸到的基本上是同 OS  HTTP 實現無關的Network 層接口。

WebKit內核源代碼分析(四)

如上是 Loader  NetWork 之間的類關係圖, ResourceHandleClient ResourceHandle 的客戶,它定義一系列虛函數,這些虛函數是 ResouceHandle 的回調,繼承類實現這些接口。

ResouceHandleClient 的接口同網絡傳輸過程息息相關,一般爲某一個網絡事件對應的回調。下面是其中的一些接口。

// 一般情況下,在發起網絡請求前調用,可以設置特定的 Http

頭部,比如 user agent 等,在重定向請求的時候,也會自動調

voidwillSendRequest(ResourceHandle*, ResourceRequest&,const

ResourceResponse&)

// 上傳數據的時候,在 TCP wrtie 事件的時候,向對方發送數據的

時候調用, loader 可以根據這個回調顯示上傳進度。

voiddidSendData(ResourceHandle*, unsigned long long

, unsigned long long)

// 收到第一個響應包,此時至少 http 的部分頭部已經解析(如

statuscode ), loader 根據響應的頭部信息判斷請求是否成功

等。

voiddidReceiveResponse(ResourceHandle*,

const   ResourceResponse&)

// 收到 HTTP 響應數據,類似 tcp  read 事件,來 http 響應數據

了, Network 的設計機制是來一段數據上傳一段數據。

voiddidReceiveData(ResourceHandle*, const char*, int,

  int)

    // 加載完成,數據來齊。

voiddidFinishLoading(ResourceHandle*, double )

// 加載失敗

voiddidFail(ResourceHandle*, constResourceError&)

// 要求用戶鑑權

voiddidReceiveAuthenticationChallenge(ResourceHandle*,

constAuthenticationChallenge&)

WebCore 把要加載的資源分成兩類,一類是主資源,比如 HTML 頁面,或者下載項,一類是派生資源,比如 HTML 頁面中內嵌的圖片或者腳本鏈接。這兩類資源對於回調的處理有很大的不同,比如,同樣是下載失敗,主資源可能需要向用戶報錯,派生資源比如頁面中的一張圖下載失敗,可能就是圖不顯示或者顯示代替說明文字而已,不向用戶報錯。因此有了 MainResourceLoader  SubresourceLoader 之分。它們的公共基類 ResourceLoader 則完成一些兩種資源下載都需要完成的操作,比如通過回調將加載進程告知上層應用。

ResourceLoader 通過 ResourceNotifier 類將回調傳導到 FrameLoaderClient 類。

WebKit內核源代碼分析(四)

主資源的加載是立刻發起的,而派生資源則可能會爲了優化網絡,在隊列中等待( 這裏的立刻發起是 loader 層面的,不是 Network 層面的 )  ResourceScheduler 這個類就是用來管理資源加載的調度。主要調度對象就是派生資源,會根據 host 來影響資源加載的先後順序。

主資源和派生資源的加載還有一個區別,主資源目前是沒有緩存的,而派生資源是有緩存機制的。這裏的緩存指的是 Resouce Cache ,用於保存原始數據(比如CSS  JS 等),以及解碼過的圖片數據,通過 Resource Cache 可以節省網絡請求和圖片解碼的時候。不同於 Page Cache  Page Cache 存的是 DOM 樹和 Render 樹的數據結構,用來在前進後退的時候快速顯示頁面。

二、加載流程

    下圖是加載 html 頁面時,一個正常的加載流程。

WebKit內核源代碼分析(四)

三、主資源加載過程

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 類)來完成操作。

 

 

 

WebKit內核源代碼分析(四)

 

各個加載階段的處理在 SubresourceLoaderClient 的派生類CachedResourceRequest,Loader,IconLoader 中完成。 Client 會創建 SubresourceLoader

請求發起階段, ResourceLoadScheduler 負責對 SubresourceLoader 進行調度。


WebKit內核源代碼分析(四)

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 類根據申請的資源類型派生出不同的子類。

 

WebKit內核源代碼分析(四)

CachedResource 類的使用者必須是 CachedResourceClient, 在這個類中維護了CachedResourceClient 類的集合 m_clients 。每一個 Client 通過 addClient removeClient 將自己加入到該類的 Client 集合中。 CachedResourceClientWalker 則提供了 CachedResouceClient 的一個遍歷接口。當數據來齊的時候, CachedResource 類會通過 CachedResouceClient::notifyFinished 接口通知使用者。

下圖是 Image 元素對應的幾個類關係。

WebKit內核源代碼分析(四)

下面以 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 對象,解碼



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章