首页 > webfront > browser > webkit > > 正文

Chrome高性能的秘密:预连接、预加载与预渲染

发布人:zhoulujun@live.cn    点击:

Chrome 使用多进程架构,将渲染进程同浏览器进程隔离开来。 Chrome 维护着一个资源分发器的实例(a single instance of the resource dispatcher), 它运行在浏览器内核进程,并在各个渲染进程间共享。

Chrome 网络架构小结

Chrome 使用多进程架构,将渲染进程同浏览器进程隔离开来。 Chrome 维护着一个资源分发器的实例(a single instance of the resource dispatcher), 它运行在浏览器内核进程,并在各个渲染进程间共享。

  • 网络层是跨平台的,大部分情况下以单进程库存在。

  • 网络层使用非阻塞式(no-blocking)操作来管理所有网络任务。

  • 共享的网络层支持有效的资源排序、复用、并为浏览器提供在多进程间进行全局优化的能力。

  • 每一个渲染进程通过 IPC 和资源分发器(resource dispatcher)通讯。

  • 资源分发器(Resource dispatcher)通过自定义的 IPC Filter 解析资源请求。

  • Predictor 在解析资源请求和响应网络事务中学习,并对后续的网络请求进行优化。

  • Predictor 会根据学习到的网络事务模式预测性的进行 DNS 解析, TCP 握手,甚至是资源请求,为用户实际操作时节省数百毫秒的时间。

了解晦涩的内部细节后,让我们来看一下用户可以感受到的优化。一切从全新的 Chrome 开始。

优化冷启动(Cold-Boot)体验

第一次启动浏览器,它当然不可能了解你的使用习惯和喜欢的页面。但事实上,我们大多数会在浏览器的冷启动后做些类似的事情,比如到电子邮箱查看邮件,加一 些新闻页面、社交页面及内部页面到我的最爱,诸如此类。这些页面各有不同,但它们仍然具有一些相似性,所以 Predictor 仍然可以对这个过程提速。

Chrome 记下了用户在全新启动浏览器时最常用的 10 个域名。当浏览器启动时,Chrome 会提前对这些域名进行 DNS 预解析。你可以在 Chrome 中使用 chrome://dns 查看到这个列表。在打开页面的最上面的表格中会列出启动时的备选域名列表。

通过 Omnibox 优化与用户的交互

引入 Omnibox 是 Chrome 的一项创新, 并不是简单地处理目标的 URL。除了记录之前访问过的页面 URL,它还与搜索引擎的整合,并且支持在历史记录中进行全文搜索(比如,直接输入页面名称)。

当用户输入时,Omnibox 自动发起一个行为,要么查找浏览记录中的 URL,要么进行一次搜索。每一次发起的操作都会被加以评分,以统计它的性能。你可以在 Chrome 输入 chrome://predictors 来观察这些数据。

Chrome 维护着一个历史记录,内容包括用户输入的前置文字,采用的行为,以命中的资数。 在上面的列表,你可以看到,当输入g时,有 76% 的机会尝试打开 Gmail. 如果再补充一个 m (就是 gm), 打开 Gmail 的可能性增加到 99.8%。

那么网络模块会做什么呢?上表中的黄色和绿色对于 ResourceDispatcher 非常重要。如果有一个一般可能性的页面(黄色), Chrome 就是发起 DNS 预解析。如果有一个高可能性的页面(绿色),Chrome 还会在 DNS 解析后发起 TCP 预连接。如果这两项都完成了,用户仍然继续录入,Chrome 就会在一个隐藏的页签进行预渲染(pre-render)。

相对的,如果输入的前置文字找不到合适的匹配项目,Chrome 会向搜索引擎服务者发起 DNS 预解析和 TCP 预连,以获取相似的搜索结果。

平均而言用户从填写查询内容到评估给出的建议需要花费数百毫秒。 此时 Chrome 可以在后台进行预解析,预连接,甚至进行预渲染。再当用户准备按下回车键时,大量的网络延迟已经被提前处理掉了。

优化缓存性能

最快的请求就是没有请求。 无论何时讨论性能,都不能不谈缓存。相信你已经为页面上所有资源的都提供了 Expires, ETag, Last-Modified 和 Cache-Control 这些响应头信息(response headers)。什么?还没有?那你还是先处理好再来看吧!

Chrome 有两种不同的内部缓存的实现:一种备份于本地磁盘(local disk),另一种则存储于内存(in-memory)中。内存模式(in-memory)主要应用于无痕浏览模式(Incognito browsing mode),并在关闭窗口清除掉。 两种方式使用了相同的内部接口(disk_cache::Backend, 和 disk_cache::Entry),大大简化了系统架构。如果你想实现一个自己的缓存算法,可以很容易地实现进去。

在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里。其中有索引文件(在浏览器启动时加载到内存中),数据文件(存储着实际数据,以及 HTTP 头以及其它信息)。比较有趣的是,16KB 以下的文件存储于共同的数据块文件中(data block-files,即小文件集中存储于一个大文件中),其它较大的文件才会存储到自己专属的文件中。最后,磁盘缓存的淘汰策略是维护一个 LRU,通过比如访问频率和资源的使用时间(age)的度量进行管理。

在 Chrome 开个页签,输入 chrome://net-internals/#httpCache。 如果你要看到实际的 HTTP 数据和缓存的响应处理,可以打开 chrome://cache, 里面会列出所有缓存中可用的资源。打开每一项,还可以看到详细的数据头等信息。