浏览器端的 9 种缓存机制
浏览器缓存是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制,有效的缓存使用可以避免重复的网络请求和浏览器快速地读取本地数据,整体上加速网页展示给用户。浏览器端缓存的机制种类较多,总体归纳为九种,这里详细分析下这九种缓存机制的原理和使用场景。打开浏览器的调试模式->resources 左侧就有浏览器的 8 种缓存机制。
一、http 缓存
http 缓存是基于 HTTP 协议的浏览器文件级缓存机制。即针对文件的重复请求情况下,浏览器可以根据协议头判断从服务器端请求文件还是从本地读取文件,chrome 控制台下的 Frames 即展示的是浏览器的 http 文件级缓存。以下是浏览器缓存的整个机制流程。主要是针对重复的 http 请求,在有缓存的情况下判断过程主要分 3 步:
- 判断 expires,如果未过期,直接读取 http 缓存文件,不发 http 请求,否则进入下一步
- 判断是否含有 etag,有则带上 if-none-match 发送请求,未修改返回 304,修改返回 200,否则进入下一步
- 判断是否含有 last-modified,有则带上 if-modified-since 发送请求,无效返回 200,有效返回 304,否则直接向服务器请求
如果通过 etag 和 last-modified 判断,即使返回 304 有至少有一次 http 请求,只不过返回的是 304 的返回内容,而不是文件内容。所以合理设计实现 expires 参数可以减少较多的浏览器请求。
二、websql
websql 这种方式只有较新的 chrome 浏览器支持,并以一个独立规范形式出现,主要有以下特点
- Web Sql 数据库 API 实际上不是 HTML5 规范的组成部分;
- 在 HTML5 之前就已经存在了,是单独的规范;
- 它是将数据以数据库的形式存储在客户端,根据需求去读取;
- 跟 Storage 的区别是: Storage 和 Cookie 都是以键值对的形式存在的;
- Web Sql 更方便于检索,允许 sql 语句查询;
- 让浏览器实现小型数据库存储功能;
- 这个数据库是集成在浏览器里面的,目前主流浏览器基本都已支持;
websql API 主要包含三个核心方法:
- openDatabase : 这个方法使用现有数据库或创建新数据库创建数据库对象。
- transaction : 这个方法允许我们根据情况控制事务提交或回滚。
- executeSql : 这个方法用于执行真实的 SQL 查询。
openDatabase 方法可以打开已经存在的数据库,不存在则创建:
var db = openDatabase('mydatabase', '2.0', my db',2*1024);
openDatabasek 中五个参数分别为:数据库名、版本号、描述、数据库大小、创建回调。创建回调没有也可以创建数据库。
database.transaction() 函数用来查询,executeSql() 用于执行 sql 语句。
例如在 mydatabase 数据库中创建表 t1:
var db = openDatabase(' mydatabase ', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function(tx){
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
});
插入操作
var db = openDatabase('mydatabase', '2.0', my db', 2 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (2, "logmsg")');
});
在插入新记录时,我们还可以传递动态值,如:
var db = openDatabase(' mydatabase ', '2.0', 'my db', 2 * 1024);
db.transaction(function(tx){
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1 (id,log) VALUES (?, ?'), [e_id, e_log]; //e_id 和 e_log 是外部变量
});
读操作,如果要读取已经存在的记录,我们使用一个回调捕获结果:
var db = openDatabase(mydatabase, '2.0', 'my db', 2*1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS t1 (id unique, log)');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO t1 (id, log) VALUES (2, "logmsg")');
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM t1, [], function (tx, results) {
var len = results.rows.length, i;
msg = "<p>Found rows: " + len + "</p>";
document.querySelector('#status').innerHTML += msg;
for (i = 0; i < len; i++){
alert(results.rows.item(i).log );
}
}, null);
});
三、indexDB
IndexedDB 是一个为了能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API。虽然 DOM 存储 对于存储少量数据是非常有用的,但是它对大量结构化数据的存储就显得力不从心了。IndexedDB 则提供了这样的一个解决方案。
IndexedDB 分别为同步和异步访问提供了单独的 API 。同步 API 本来是要用于仅供 Web Workers 内部使用,但是还没有被任何浏览器所实现。异步 API 在 Web Workers 内部和外部都可以使用,另外浏览器可能对 indexDB 有 50M 大小的限制,一般用户保存大量用户数据并要求数据之间有搜索需要的场景。
异步 API
异步 API 方法调用完后会立即返回,而不会阻塞调用线程。要异步访问数据库,要调用 window 对象 indexedDB 属性的 open() 方法。该方法返回一个 IDBRequest 对象 (IDBOpenDBRequest);异步操作通过在 IDBRequest 对象上触发事件来和调用程序进行通信。
- IDBFactory 提供了对数据库的访问。这是由全局对象 indexedDB 实现的接口,因而也是该 API 的入口。
- IDBCursor 遍历对象存储空间和索引。
- IDBCursorWithValue 遍历对象存储空间和索引并返回游标的当前值。
- IDBDatabase 表示到数据库的连接。只能通过这个连接来拿到一个数据库事务。
- IDBEnvironment 提供了到客户端数据库的访问。它由 window 对象实现。
- IDBIndex 提供了到索引元数据的访问。
- IDBKeyRange 定义键的范围。
- IDBObjectStore 表示一个对象存储空间。
- IDBOpenDBRequest 表示一个打开数据库的请求。
- IDBRequest 提供了到数据库异步请求结果和数据库的访问。这也是在你调用一个异步方法时所得到的。
- IDBTransaction 表示一个事务。你在数据库上创建一个事务,指定它的范围(例如你希望访问哪一个对象存储空间),并确定你希望的访问类型(只读或写入)。
- IDBVersionChangeEvent 表明数据库的版本号已经改变。
同步 API
规范里面还定义了 API 的同步 版本。同步 API 还没有在任何浏览器中得以实现。它原本是要和 webWork 一起使用的。
四、cookie
Cookie(或者 Cookies),指一般网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。cookie 一般通过 http 请求中在头部一起发送到服务器端。一条 cookie 记录主要由键、值、域、过期时间、大小组成,一般用户保存用户的认证信息。cookie 最大长度和域名个数由不同浏览器决定,具体如下:
浏览器 | 支持域名个数 | 最大长度 |
---|---|---|
IE7 以上 | 50 个 | 4095B |
Firefox | 50 个 | 4097B |
Opera | 30 个 | 4096B |
Safari/WebKit | 无限制 | 4097B |
不同域名之间的 cookie 信息是独立的,如果需要设置共享可以在服务器端设置 cookie 的 path 和 domain 来实现共享。浏览器端也可以通过 document.cookie 来获取 cookie,并通过 js 浏览器端也可以方便地读取/设置 cookie 的值。
https://github.com/component/cookie/blob/master/index.js
五、localstorage
localStorage 是 html5 的一种新的本地缓存方案,目前用的比较多,一般用来存储 ajax 返回的数据,加快下次页面打开时的渲染速度。
浏览器 | 最大长度 |
---|---|
IE9 以上 | 5M |
Firefox 8 以上 | 5.24M |
Opera | 2M |
Safari/WebKit | 2.6M |
//localStorage 核心 API:
localStorage.setItem(key, value) //设置记录
localStorage.getItem(key) //获取记录
localStorage.removeItem(key) //删除该域名下单条记录
localStorage.clear() //删除该域名下所有记录
值得注意的是,localstorage 大小有限制,不适合存放过多的数据,如果数据存放超过最大限制会报错,并移除最先保存的数据。
https://github.com/machao/localStorage
六、sessionstorage
sessionStorage 和 localstorage 类似,但是浏览器关闭则会全部删除,api 和 localstorage 相同,实际项目中使用较少。
七、application cache
application cahce 是将大部分图片资源、js、css 等静态资源放在 manifest 文件配置中。当页面打开时通过 manifest 文件来读取本地文件或是请求服务器文件。
离线访问对基于网络的应用而言越来越重要。虽然所有浏览器都有缓存机制,但它们并不可靠,也不一定总能起到预期的作用。HTML5 使用 ApplicationCache 接口可以解决由离线带来的部分难题。前提是你需要访问的 web 页面至少被在线访问过一次。
使用缓存接口可为您的应用带来以下三个优势:
- 离线浏览 – 用户可在离线时浏览您的完整网站
- 速度 – 缓存资源为本地资源,因此加载速度较快。
- 服务器负载更少 – 浏览器只会从发生了更改的服务器下载资源。
一个简单的离线页面主要包含以下几个部分:
index.html
<htmlmanifest="clock.manifest">
<head>
<title>AppCache Test</title>
<linkrel="stylesheet"href="clock.css">
<script src="clock.js"></script>
</head>
<body>
<p><outputid="clock"></output></p>
<divid="log"></div>
</body>
</html>
clock.manifest
CACHE MANIFEST
#VERSION 1.0
CACHE:
clock.css
clock.js
clock.js 和 clock.css 为独立的另外文件。
另外需要注意的是更新缓存。在程序中,你可以通过 window.applicationCache 对象来访问浏览器的 app cache。你可以查看 status 属性来获取 cache 的当前状态:
var appCache = window.applicationCache;
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};
为了通过编程更新 cache,首先调用 applicationCache.update()。这将会试图更新用户的 cache(要求 manifest 文件已经改变)。最后,当 applicationCache.status 处于 UPDATEREADY 状态时, 调用 applicationCache.swapCache(),旧的 cache 就会被置换成新的。
var appCache = window.applicationCache;
appCache.update(); // Attempt to update the user’s cache.
…
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // The fetch was successful, swap in the new cache.
}
这里是通过更新 menifest 文件来控制其它文件更新的。
八、cacheStorage
CacheStorage 是在 ServiceWorker 的规范中定义的。CacheStorage 可以保存每个 serverWorker 申明的 cache 对象,cacheStorage 有 open、match、has、delete、keys 五个核心方法,可以对 cache 对象的不同匹配进行不同的响应。
cacheStorage.has()
如果包含 cache 对象,则返回一个 promise 对象。
cacheStorage.open()
打开一个 cache 对象,则返回一个 promise 对象。
cacheStorage.delete()
删除 cache 对象,成功则返回一个 promise 对象,否则返回 false。
cacheStorage.keys()
含有 keys 中字符串的任意一个,则返回一个 promise 对象。
cacheStorage.delete()
匹配 key 中含有该字符串的 cache 对象,返回一个 promise 对象。
caches.has('v1').then(function(){
caches.open('v1').then(function(cache){
return cache.addAll(myAssets);
});
}).catch(function(){
someCacheSetupfunction();
});;
var response;
var cachedResponse = caches.match(event.request).catch(function(){
return fetch(event.request);
}).then(function(r){
response = r;
caches.open('v1').then(function(cache){
cache.put(event.request, response);
});
return response.clone();
}).catch(function(){
return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
then.addEventListener('activate', function(event){
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList){
return Promise.all(keyList.map(function(key){
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(keyList[i]);
}
});
})
);
});
https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage
九、flash 缓存
这种方式基本不用,这一方法主要基于 flash 有读写浏览器端本地目录的功能,同时也可以向 js 提供调用的 api,则页面可以通过 js 调用 flash 去读写特定的磁盘目录,达到本地数据缓存的目的。
注释 PS
- Web Storage / Web SQL Database / Indexed Database 的数据都存储在浏览器对应的用户配置文件目录(user profile directory) 下,以 Windows 7 为例,Chrome 的数据存储在”C:\Users\your-account-name\AppData\Local\Google\Chrome\User Data\Default\”下,而 Firefox 的数据存储在”C:\Users\your-account-name\AppData\Local\Mozilla\Firefox\Profiles\”目录下。
cookie 文件存储于 documents and settings\userName\cookie\文件夹下。通常的命名格式为: userName@domain.txt 。
较多的缓存机制目前主流浏览器并不兼容,不过可以使用 polyfill 的方法来处理
浏览器涉及的缓存方式主要包含这些,具体结合自己的业务场景进行选择使用
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论