网络栈和资源加载
此内容为笔者学习和自我总结,有错误的地方请谅解和指出,笔者定会及时更正。学习的路上,一起互助前行。
这里,我们讲一下chrome中有关资源的加载。从用户输入url到chrome浏览器加载资源的过程,以及怎么资源进行高效的管理。
-
先介绍下资源加载的基础设施
1)HTML资源支持的类型。包括:
a. HTML:HTML页面,包括各种各样的HTML元素。
b. JS:js代码。可以是内嵌的,也可以是单独的文件。
c. CSS样式表:css样式资源。可以是内嵌的,也可以是单独的文件。
d. 图片。
e. 字体文件。
f. 等...资源加载器:分类以及大概作用。
1) 针对每种资源类型的特定加载器。其特点是仅加载某一种资源。ImageLoader类仅加载图片资源。
2)资源缓存机制的资源加载器。特点是所有加载器都需要通过它来检查和插入缓存资源。
3)通用资源加载器--ResourceLoader类。当webkit需要从网络或者文件系统获取资源时负责获取资源的数据。
webkit以这样的方式设计加载器,目的是想将加载的复杂机制逐渐简化为若干简单步骤。这些资源在webkit中都有不同的类表示,这些类的公共基类是CachedResource。比如:CachedScript存储js资源,CachedCssStyleSheet类存储样式表,等。
那为什么基类是'Cached'字样呢?这里是因为资源加载的效率问题引入了缓存机制,它对资源的请求都会先获取缓存中的信息,以决定是否向服务器请求资源。那什么是资源的缓存呢?
2)资源缓存
这里主要说的缓存位置:内存缓存(memory cache),磁盘缓存(disk cache);当然还有service worker 缓存,以及http2协议涉及的Push Cache。
a. 内存资源的缓存机制的基本思路:
建立一个资源的缓存池,当webkit请求资源时,先从资源池中查看有没有响应资源。有则取出使用。如果没有,webkit会先创建一个新的CachedResource子类的对象,等待webkit收到资源后,以url为资源的唯一标识符,将其资源设置到新的CachedResource子类的对象中,待下次使用。
内存缓存固然快,不过内存存在时间较短,当相应进程释放,内存缓存也会被清除。b. 磁盘本地缓存 为了进一步提升资源的加载效率(当进程释放后,再进入时,资源其实没有改变的),提出磁盘缓存机制。把资源存储在本地磁盘中。 1)磁盘存储的结构 数据以表的形式存储在磁盘上。分索引文件,和数据文件(块文件)。 1.1) 索引文件: 用来方便快速检索存放在数据文件中的索引项。包括索引头,和索引地址。索引文件直接将文件映射到内存地址(个人感觉应该是逻辑地址),方便快速找到表项的索引地址。 头部包括:索引版本号,索引项数目,文件大小等。 索引地址:保存各个表项对应的索引地址。 1.2)数据文件(块文件) 由很多特定大小的块组成,数据块的内容是表项。表项结构可以大致分为两部分: a. 用于数据标记的内容。包括元数据信息,自身内容,通常比较少变动。 b. 包括回收算法服务所需信息,具体存储数据信息(也很可能是指向具体信息存放的地址)。更多详情,可参照如下:Disk Cache:www.chromium.org/developers/…
想比于内存缓存,磁盘能存的多,时间也可以更长,但磁盘的读取效率低。不过chrome中,具体怎么权衡数据什么时候该缓存在内存中,什么时候该缓存在磁盘中,或者说什么资源应该缓存在内存或磁盘中?
笔者比较认可的说法是:(根据内存和磁盘功能来分)
1. 大文件,通常优先存磁盘。 2. 进程未释放,内存空间足够,该进程加载的资源需要缓存的话,优先内存缓存。 3. 内存紧张时,优先磁盘缓存。进程要释放时,内存中的资源可以有选择的存入磁盘。当代浏览器一般的查找缓存顺序:(查询还要带上浏览器缓存策略的条件)
- service worker 缓存
- memory cache
- dist cache
- push cache (http2) 都没命中,再会请求网络。(比如协商缓存)
-
资源加载的过程。
当在浏览器输入一个url时:当前tab页的Render进程会将该资源获取的任务通过进程间通信,交给Browser进程来实现,这里是为了安全性和效率。Browser进程有权限从网络或者本地获取资源。
1)判断是否有缓存:
以此查看service worker缓存,内存缓存,磁盘缓存,(如果时http2,再查看push cache)是否有命中。如果完全命中,从缓存中获取信息。一个资源该不该缓存,该怎么缓存?这个主要由服务器返回信息决定,浏览器根据服务端响 应的请求信息判断是否缓存和怎么缓存。
那缓存涉及的http信息字段有哪些呢?http缓存过程有哪些呢?
分强缓存和协商缓存。 这里还有注意一个前提:http协议中有规范规定,浏览器可以发送消息确认是否需要更新请求信息。 1. 强缓存: a. 在http/1.0 中,根据响应头的Expires来判断,它表明的是资源失效时间点。
b. 在http/1.1 中引入 Cache-Control,它可以在请求头或者响应头中设置,并且可以组合使用多种指令。
响应通常设置max-age=来设置缓存存储的最大周期,单位是秒。
2. 协商缓存: 若强缓存信息判断失效,则进行协商缓存
a. ETag 标识符:请求(资源)响应的响应头特定版本的标识符; 每次资源更改(毫秒级),会生成新的ETag值。对比max-age,更准确和灵活。 客户端请求时,可以配合If-Match头来检查是否为最新版,或者配合If-None-Match检查 客户端显示已过期且不可用的资源 在服务端是否更改。
b. 服务端-Last-Modified
客户端 If-Modified-Since 或者If-None-Match 配合使用;2)如果没有命中任何缓存(协商缓存没有协商成功,还需要从服务端获取)。则
2.1)DNS域名解析:
在chromium 中,使用HostResolverImpl类的g"etaddrinfo()"方法来解析域名,这是一个阻塞式的函数,所以chromium会使用单独的线程来做域名解析。
chromium对于域名解析的优化还有预解析方式。大概思想是:利用现有的DNS机制,提前解析网页中可能的网络连接。这里要注意可能,也就是说是一种猜测。比如用户在输入url的过程中,不断的根据已输入的字符,去猜测可能的url,提前建立连接。或者通过大数据来预测行为,推测可能性,提前建立连接。
或者在解析HTML文档时,设置的dns-prefetch标示,当解析被js的同步请求阻碍时,可以单独建立线程,扫描文档中是否有有类似标识,记录标示信息,提前做DNS解析和下载资源。2.2)建立网络连接 应用层 http协议 会话层 SPDY协议 表示层 SSL协议 传输层 TCP/UDP协议 网络层 ip 从上往下,先说http协议,http/1.0时,每一次http请求,需要等待TCP连接。 到http/1.1,通过管道(管线化)技术,只有在GET和HED等请求可行。优化http协议,通过服务端配合,开启永久连接,可以使用多个请求共用一次TCP连接(也就是把多个http数据填充在一个TCP数据包中),减少网络负载。但是请求还是有明显的先后顺序,(没有识别每个数据包的情况)所以需要按顺序返回。 为了解决上述问题,在会话层SPDY协议,真正意义上实现了多路复用。也是http/2.0的基础。 SPDY协议的核心,多路复用-也就是一个TCP连接,实现多个资源传输。 此外,也有二进制传输,头部压缩,服务端主动推送,区分资源请求的优先级等。
---待续,未完---