webkit的主资源与派生资源
前端性能优化中,减少HTTP请求可以提高页面的响应速度。
浏览器在第一次访问页面时向服务器请求资源,并缓存起来,下次再访问时会判断在缓存中是否已有该资源且有没有更新过,如果已有该资源且未更新过,则直接从浏览器缓存中读取。原理:通过HTTP 请求头中的 If-Modified-Since(If-No-Match) 和响应头中的Last-Modified(ETag)来实现,HTTP请求把 If-Modified-Since(If-No-Match)传给服务器,服务器将其与Last-Modified(ETag)对比,若相同,则文件没有被改动过,则返回304,直接浏览器缓存中读取资源即可。
问题:虽然该方法减少了已缓存资源的下载时间,但仍然发起了一次http请求。
解决:已缓存资源不再发起http请求,即HTTP的Expires和Cache-Control。对一个网站而言,CSS、JavaScript、图片等静态资源更新的频率都比较低,而这些文件又几乎是每次HTTP请求都需要的,如果将这些文件缓存在浏览器中,可以极好的改善性能。通过设置http头中的cache-control和expires的属性,可设定浏览器缓存,将静态内容设为永不过期,或者很长时间后才过期。
1、Cache-Control
Cache-Control属性是在服务器端配置的,不同的服务器有不同的配置,apache、nginx、IIS、tomcat等配置都不尽相同。
以Apache为例,在http.conf中做如下配置:
- <filesMatch ”.(jpg|jpeg|png|gif|ico)$”>
- Header set Cache Control max-age=16768000,public
- </filesMatch>
- <filesMatch ”.(css|js)$”>
- Header set Cache Control max-age=2628000,public
- </filesMatch>
问题:浏览器缓存的资源,若又想更新资源,如何实现?
解决:通过修改该资源的名称来实现。修改了资源名称,浏览器会当做不同的资源。
2、Expires
Expires属性也是在服务端配置的,具体的配置也根据服务器而定。
问题:可能存在客户端时间跟服务端时间不一致的问题。
解决:建议Expires结合Cache-Control一起使用。
3、测试实例:
1) 未使用expires和cache-control的测试demo:
打开网址:http://stevesouders.com/hpws/expiresoff.php (发送请求了,返回的是304)
2) 使用expires和cache-control的测试demo:
打开网址:http://stevesouders.com/hpws/expireson.php(连请求都没有发送)
在过去,Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本、样式表链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。这两类资源的加载过程颇有不同,比如对资源加载失败的处理,主资源下载失败会有报错提示,而派生资源如图片下载失败,往往只显示一个占位符。所以网络加载模块分别设计了MainResourceLoader和SubresourceLoader来处理它们。它们的公共基类ResourceLoader主要完成两种资源加载都需要进行的操作,如在资源加载过程中,反馈加载状态的回调等。
WebCore 把要加载的资源分成两类,一类是主资源,比如 HTML 页面,或者下载项,一类是派生资源,比如 HTML 页面中内嵌的图片或者脚本链接。这两类资源对于回调的处理有很大的不同,比如,同样是下载失败,主资源可能需要向用户报错,派生资源比如页面中的一张图下载失败,可能就是图不显示或者显示代替说明文字而已,不向用户报错。因此有了 MainResourceLoader 和 SubresourceLoader 之分。
WebCore 把要加载的资源分成两类,一类是主资源,比如 HTML 页面,或者下载项,一类是派生资源,比如 HTML 页面中内嵌的图片或者脚本链接。这两类资源对于回调的处理有很大的不同,比如,同样是下载失败,主资源可能需要向用户报错,派生资源比如页面中的一张图下载失败,可能就是图不显示或者显示代替说明文字而已,不向用户报错。因此有了 MainResourceLoader 和 SubresourceLoader 之分。它们的公共基类 ResourceLoader 则完成一些两种资源下载都需要完成的操作,比如通过回调将加载进程告知上层应用。
主资源的加载是立刻发起的,而派生资源则可能会为了优化网络,在队列中等待( 这里的立刻发起是 loader 层面的,不是 Network 层面的 ) 。 ResourceScheduler 这个类就是用来管理资源加载的调度。主要调度对象就是派生资源,会根据 host 来影响资源加载的先后顺序。
主资源和派生资源的加载还有一个区别,主资源目前是没有缓存的,而派生资源是有缓存机制的。这里的缓存指的是 Resouce Cache ,用于保存原始数据(比如CSS , JS 等),以及解码过的图片数据,通过 Resource Cache 可以节省网络请求和图片解码的时候。不同于 Page Cache , Page Cache 存的是 DOM 树和 Render 树的数据结构,用来在前进后退的时候快速显示页面。
注:自从WebKit有了PageCache(主资源也可以缓存)的功能以后。WebKit资源加载已经不区分MainResourceLoader和SubresourceLoader,统一由CachedResourceLoader加载资源,而区分主资源和派生资源则是通过CachedResource类里面Type类型:
enum Type {
MainResource,
ImageResource,
CSSStyleSheet,
Script,
FontResource,
RawResource
};
可以看到加载主资源的时候,Type类型就为MainResource。由于目前我们使用的WebKit代码已经使用了比较新的代码,所以本章后面介绍的流程都与过去的流程不一样了。
WebKit派生资源包含的类型主要如下:
Javascript脚本(CachedScript);
CSS样式文本(CachedCSSStyleSheet);
图片(CachedImage);
字体(CachedFont);
XSL样式表(CachedXSLStyleSheet);
可以说除了主资源剩下的网络资源都是派生资源。派生资源的WebKit中都有对应的类实现,它们有着共同的基类(CachedResource),下面是类图:
今天在做项目的优化的时候,使用chrome开发者工具的network发现了细节:
虽然这两个看起来都是从缓存中读取,但还是有一些不一样的!
webkit资源的分类
webkit的资源分类主要分为两大类:主资源和派生资源
http状态码
200 from memory cache
不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当kill进程后,也就是浏览器关闭以后,数据将不存在。
但是这种方式只能缓存派生资源。
200 from disk cache
不访问服务器,直接读缓存,从磁盘中读取缓存,当kill进程时,数据还是存在。
这种方式也只能缓存派生资源
304 Not Modified
访问服务器,发现数据没有
更新,服务器返回此状态码。然后从缓存中读取数据。
但是这里有困惑,怎么判断from memory cache还是304
三级缓存原理
- 先去内存看,如果有,直接加载
- 如果内存没有,择取硬盘获取,如果有直接加载
- 如果硬盘也没有,那么就进行网络请求
- 加载到的资源缓存到硬盘和内存
所以我们可以来解释这个现象
图片为例:
访问-> 200 -> 退出浏览器
再进来-> 200(from disk cache) -> 刷新 -> 200(from memory cache)
http header
max-age
web中的文件被用户访问(请求)后的存活时间,是个相对的值,相对Request_time(请求时间)
Expires
Expires指定的时间根据服务器配置可能有两种:
- 文件最后访问时间
- 文件绝对修改时间
如果max-age和Expires同时存在,则被Cache-Control的max-age覆盖
last-modified
WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间
ETag
对象(比如URL)的标志值,就一个对象而言,文件被修改,Etag也会修改
Cache-Control
简单理解,强缓存
最后结论
见图片(来源自网络)
链接:https://www.jianshu.com/p/444f3b7fcc63
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。