第四章 资源加载和网络栈
使用网络栈来下载网页和网页资源是渲染引擎工作的第一步
1.WebKit 资源加载机制
1.1 资源
网页本身就是一种资源、网页还需要依赖很多其他的资源(图片、视频)
(1)HTML 支持的资源主要包括以下几种类型:
HTML 页面,包括各式各样的HTML元素
- JavaScript
- CSS
- 图片
- SVG
- CSS Shader
- 音频、视频、文字
- 字体文件
- XSL样式表:使用XSLT语言编写的XSLT代码文件
(2)在webkit种通过不同的类来表示这些资源,webkit为这些资源提供了一个公共基类 CachedResource
(3)Webkit 资源类
- 公共基类是CachedResource,各种资源以其子类的方式存在
HTML文本在WebKit中,类型叫MainResource类,与其对应的资源类型叫CachedRawResource类。
这些类都有Cached前缀,是因为效率问题而引入的缓存机制,所有对资源的请求都会先获取缓存中的信息,以决定服务器提出资源请求。
1.2 资源缓存:
使用资源缓存是为了提高资源的利用率。 基本思想是建立一个资源的缓存池,当 WebKit 需要请求资源时,先从资源池中查找是否存在相应的资源(根据资源的 URL 标识不同资源),如果有则取出以便使用,没有就创建一个新的 CachedResource 子类对象,发送真正的请求给服务器,WebKit 收到资源后将其设置到该资源类的对象中去,以便于缓存(这里的缓存指内存缓存)后下次使用。这里的缓存指的是内存缓存,而不同于后面在网络栈部分的磁盘缓存。
WebKit从资源池中查找资源的关键字是URL,因为标记资源唯一性的特征就是资源的URL。这也意味着,假如两个资源有不同的URL,但是它们的内容完全一样,也被认为是两个不同的资源。
1.3 资源加载器
WebKit有三种类型的加载器:
- 针对每种资源类型的特定加载器:仅加载某一种资源。对于image对应是特定资源加载器是ImageLoader类,对于CSS自定义字体,它的特定资源加载器是Font Loader类。这些资源加载器没有公共基类,其作用就是当需要请求资源时,由资源加载器负责加载并隐藏背后复杂的逻辑。加载器属于它的调用者。
- 资源缓存机制的资源加载器:所有特定加载器都共享它来查找并插入缓存资源,CachedResourceLoader 类,特定加载器首先是通过缓存机制的资源加载器来查找是否有缓存资源,它属于 HTML 文档对象。
- 通用资源加载器:ResourceLoader 类,在 WebKit 需要从网络或者文件系统获取资源的时候使用 ResourceLoader 类只负责获得资源的数据,因此被所有特定资源加载器所共享,它属于 CachedResource 类。但它同CachedResourceLoader类没有继承关系(这点容易混淆)。
这样设计WebKIt加载器,主要是为了将其中的复杂机制逐渐简化为若干简单的步骤。
1.4 加载过程:
通常一些资源的加载时异步的(如图片、css文件),其获取和加载不会阻碍当前 WebKit 的渲染过程。
但特殊资源如 JavaScript 代码文件的加载会阻碍主线程的渲染过程,这会严重影响 WebKit 下载资源的效率,后面可能还有许多需要下载的资源。 WebKit 的做法是:当前主线程被阻碍,启动另外一个线程去遍历后面的 HTML 网页,收集需要的资源的 URL,然后发送请求,同时能够并发下载这些资源(甚至 JavaScript 代码资源)。
1.5 资源的生命周期:
资源池中的资源生命周期:LRU 算法(Least Recent Used 最近最少使用)
对于判断下次使用的时候是否需要更新该资源(服务器可能在某段时间之后更新了该资源):WebKit 的做法是首先判断资源是否在资源池中,如果是则发送一个 HTTP 请求给服务器说明该资源在本地的一些信息,服务器更具该信息作判断,如果没有更新则发送回状态码 304(缓存命中)表明无需更新,直接利用资源池中原来的资源,否则 WebKit 申请下载最新的资源内容(这里可以参考 http权威指南 中的缓存模块)。可以通过开发者工具中的 network 打开或关闭此机制,实现的原理就是直接清除 MemoryCache 对象中的所有资源(全局唯一),清除该资源后就会重新打开缓存机制,这样就会在资源池中找不到所要请求的资源,请求报文中就不会有条件首部字段。
1.6 资源缓存实践
设置取消缓存的调用栈,可以看到缓存的资源的关系。