html5本次存储几种方式

1、cookies

  你们都懂的,没必要多说javascript

2、sessionStorage/localStorage

HTML5 LocalStorage 本地存储css

说到本地存储,这玩意真是历尽千辛万苦才走到HTML5这一步,以前的历史大概以下图所示:html

 

最先的Cookies天然是你们都知道,问题主要就是过小,大概也就4KB的样子,并且IE6只支持每一个域名20cookies,太少了。优点就是你们都支持,并且支持得还蛮好。很早之前那些禁用cookies的用户也都慢慢的不存在了,就好像之前禁用javascript的用户不存在了同样。html5

 

userDataIE的东西,垃圾。如今用的最多的是Flash吧,空间是Cookie25倍,基本够用。再以后Google推出了Gears,虽然没有限制,但不爽的地方就是要装额外的插件(没具体研究过)。到了HTML5把这些都统一了,官方建议是每一个网站5MB,很是大了,就存些字符串,足够了。比较诡异的是竟然全部支持的浏览器目前都采用的5MB,尽管有一些浏览器可让用户设置,但对于网页制做者来讲,目前的形势就5MB来考虑是比较稳当的。java



支持的状况如上图,IE8.0的时候就支持了,很是出人意料。不过须要注意的是,IEFirefox测试的时候须要把文件上传到服务器上(或者localhost),直接点开本地的HTML文件,是不行的。web

 

首先天然是检测浏览器是否支持本地存储。在HTML5中,本地存储是一个window的属性,包括localStoragesessionStorage,从名字应该能够很清楚的辨认两者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。两者用法彻底相同,这里以localStorage为例。数据库

if(window.localStorage){
 alert('This browser supports localStorage');
}else{
 alert('This browser does NOT support localStorage');
}编程

 

存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a 或者 window.localStorage["a"]。它的读取、写、删除操做方法很简单,是以键值对的方式存在的,以下:json

localStorage.a = 3;//设置a"3"
localStorage["a"] = "sfsf";//设置a"sfsf",覆盖上面的值
localStorage.setItem("b","isaac");//设置b"isaac"
var a1 = localStorage["a"];//获取a的值
var a2 = localStorage.a;//获取a的值
var b = localStorage.getItem("b");//获取b的值
localStorage.removeItem("c");//清除c的值
后端

 

这里最推荐使用的天然是getItem()setItem(),清除键值对使用removeItem()。若是但愿一次性清除全部的键值对,可使用clear()。另外,HTML5还提供了一个key()方法,能够在不知道有哪些键值的时候使用,以下:

var storage = window.localStorage;
function showStorage(){
 for(var i=0;i<storage.length;i++){
  //key(i)得到相应的键,再用getItem()方法得到对应的值
  document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
 }
}

 

写一个最简单的,利用本地存储的计数器:

var storage = window.localStorage;
if (!storage.getItem("pageLoadCount")) storage.setItem("pageLoadCount",0);
storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必须格式转换
document.getElementByIdx_x("count").innerHTML = storage.pageLoadCount;
showStorage();

不断刷新就能看到数字在一点点上涨,以下图所示:

 

须要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,因此读取的时候,须要本身进行类型的转换。这也就是上一段代码中parseInt必需要使用的缘由。

 

另外,在iPhone/iPad上有时设置setItem()时会出现诡异的QUOTA_EXCEEDED_ERR错误,这时通常在setItem以前,先removeItem()ok了。

 

HTML5的本地存储,还提供了一个storage事件,能够对键值对的改变进行监听,使用方法以下:

if(window.addEventListener){
 window.addEventListener("storage",handle_storage,false);
}else if(window.attachEvent){
 window.attachEvent("onstorage",handle_storage);
}
function handle_storage(e){
 if(!e){e=window.event;}
 //showStorage();
}

 

对于事件变量e,是一个StorageEvent对象,提供了一些实用的属性,能够很好的观察键值对的变化,以下表:

 Property

 Type

 Description

 key

 String

 The named key that was added, removed, or moddified

 oldValue

 Any

 The previous value(now overwritten), or null if a new item was added

 newValue

 Any

 The new value, or null if an item was added

 url/uri

 String

 The page that called the method that triggered this change

 

这里添加两个键值对ab,并增长一个按钮。给a设置固定的值,当点击按钮时,修改b的值:

<body>
<p>You have viewed this page <span id="count">0</span>  time(s).</p>
<p><input type="button" value="changeStorage" onClick="changeS()"/></p>
<script>
var storage = window.localStorage;
if (!storage.getItem("pageLoadCount")) storage.setItem("pageLoadCount",0);
storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必须格式转换
document.getElementByIdx_x("count").innerHTML = storage.pageLoadCount;
showStorage();
if(window.addEventListener){
 window.addEventListener("storage",handle_storage,false);
}else if(window.attachEvent){
 window.attachEvent("onstorage",handle_storage);
}
function handle_storage(e){
 if(!e){e=window.event;}
 showObject(e);
}
function showObject(obj){
 //递归显示object
 if(!obj){return;}
 for(var i in obj){
  if(typeof(obj[i])!="object" || obj[i]==null){
   document.write(i + " : " + obj[i] + "<br/>");
  }else{
   document.write(i + " : object" + "<br/>");
  }
 }
}
storage.setItem("a",5);
function changeS(){
 //修改一个键值,测试storage事件
 if(!storage.getItem("b")){storage.setItem("b",0);}
 storage.setItem('b',parseInt(storage.getItem('b'))+1);
}
function showStorage(){
 //循环显示localStorage里的键值对
 for(var i=0;i<storage.length;i++){
  //key(i)得到相应的键,再用getItem()方法得到对应的值
  document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
 }
}
</script>
</body>

 

测试发现,目前浏览器对这个支持不太好,仅iPadFirefox支持,并且Firefox支持得乱糟糟,e对象根本没有那些属性。iPad支持很是好,用的是e.uri(不是e.url),台式机上的Safari不行,诡异。

 

目前浏览器都带有很好的开发者调试功能,下面分别是ChromeFirefox的调试工具查看LocalStorage



另外,目前javascript使用很是多的json格式,若是但愿存储在本地,能够直接调用JSON.stringify()将其转为字符串。读取出来后调用JSON.parse()将字符串转为json格式,以下所示:

var details = {author:"isaac","description":"fresheggs","rating":100};
storage.setItem("details",JSON.stringify(details));
details = JSON.parse(storage.getItem("details"));

 

JSON对象在支持localStorage的浏览器上基本都支持,须要注意的是IE8,它支持JSON,但若是添加了以下的兼容模式代码,切到IE7模式就不行了(此时依然支持localStorage,虽然显示window.localStorage[object],而不是以前的[object Storage],但测试发现getItem()setItem()等均能使用)。

<meta content="IE=7" http-equiv="X-UA-Compatible"/>

3、web SQL / indexedDB

咱们常常在数据库中处理大量结构化数据,html5引入Web SQL Database概念,它使用 SQL 来操纵客户端数据库的 API,这些 API 是异步的,规范中使用的方言是SQLlite,悲剧正是产生于此,Web SQL Database规范页面有着这样的声明

image

This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path.

 大概意思就是

这个文档曾经在W3C推荐规范上,但规范工做已经中止了。目前已经陷入了一个僵局:目前的全部实现都是基于同一个SQL后端(SQLite),可是咱们须要更多的独立实现来完成标准化。

也就是说这是一个废弃的标准了,虽然部分浏览器已经实现,但。。。。。。。

三个核心方法

可是咱们学一下也没什么坏处,并且能和如今W3C力推的IndexedDB作比较,看看为何要废弃这种方案。Web SQL Database 规范中定义的三个核心方法:

  1. openDatabase:这个方法使用现有数据库或新建数据库来建立数据库对象
  2. transaction:这个方法容许咱们根据状况控制事务提交或回滚
  3. executeSql:这个方法用于执行SQL 查询

 

openDatabase

咱们可使用这样简单的一条语句,建立或打开一个本地的数据库对象

var db = openDatabase('testDB', '1.0', 'Test DB', 2 * 1024 * 1024);

openDatabase接收五个参数:

  1. 数据库名字
  2. 数据库版本号
  3. 显示名字
  4. 数据库保存数据的大小(以字节为单位 )
  5. 回调函数(非必须)

 

若是提供了回调函数,回调函数用以调用 changeVersion() 函数,无论给定什么样的版本号,回调函数将把数据库的版本号设置为空。若是没有提供回调函数,则以给定的版本号建立数据库。

transaction

transaction方法用以处理事务,当一条语句执行失败的时候,整个事务回滚。方法有三个参数

  1. 包含事务内容的一个方法
  2. 执行成功回调函数(可选)
  3. 执行失败回调函数(可选)

 

复制代码
db.transaction(function (context) {
           context.executeSql('CREATE TABLE IF NOT EXISTS testTable (id unique, name)');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (0, "Byron")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (1, "Casper")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (2, "Frank")');
         });
复制代码

这个例子中咱们建立了一个table,并在表中插入三条数据,四条执行语句任何一条出现错误,整个事务都会回滚

executeSql

executeSql方法用以执行SQL语句,返回结果,方法有四个参数

  1. 查询字符串
  2. 用以替换查询字符串中问号的参数
  3. 执行成功回调函数(可选)
  4. 执行失败回调函数(可选)

在上面的例子中咱们使用了插入语句,看个查询的例子

复制代码
db.transaction(function (context) {
           context.executeSql('SELECT * FROM testTable', [], function (context, results) {
            var len = results.rows.length, i;
            console.log('Got '+len+' rows.');
               for (i = 0; i < len; i++){
              console.log('id: '+results.rows.item(i).id);
              console.log('name: '+results.rows.item(i).name);
            }
         });
复制代码

完整示例

复制代码
<!DOCTYPE HTML>
<html>
<head>
    <title>Web SQL Database</title>
</head>
<body>
    <script type="text/javascript">
        var db = openDatabase('testDB', '1.0', 'Test DB', 2 * 1024 * 1024);
        var msg;
        db.transaction(function (context) {
           context.executeSql('CREATE TABLE IF NOT EXISTS testTable (id unique, name)');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (0, "Byron")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (1, "Casper")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (2, "Frank")');
         });

        db.transaction(function (context) {
           context.executeSql('SELECT * FROM testTable', [], function (context, results) {
            var len = results.rows.length, i;
            console.log('Got '+len+' rows.');
               for (i = 0; i < len; i++){
              console.log('id: '+results.rows.item(i).id);
              console.log('name: '+results.rows.item(i).name);
            }
         });
        });
    </script>
</body>
</html>
复制代码

最后

因为Web SQL Database规范已经被废弃,缘由说的很清楚,当前的SQL规范采用SQLite的SQL方言,而做为一个标准,这是不可接受的,每一个浏览器都有本身的实现这还搞毛的标准。这样浏览器兼容性就不重要了,估计慢慢会被遗忘。不过Chrome的控制台真心好用啊,神马cookie、Local Storage、Session Storage、Web SQL、IndexedDB、Application Cache等html5新增内容看的一清二楚,免去了不少调试代码工做。

image

 

4、application Cahe

一、应用场景

离线访问对基于网络的应用而言愈来愈重要。虽然全部浏览器都有缓存机制,但它们并不可靠,也不必定总能起到预期的做用。HTML5 使用ApplicationCache 接口解决了由离线带来的部分难题。前提是你须要访问的web页面至少被在线访问过一次。

二、使用缓存接口可为您的应用带来如下三个优点:
离线浏览 – 用户可在离线时浏览您的完整网站
速度 – 缓存资源为本地资源,所以加载速度较快。
服务器负载更少 – 浏览器只会从发生了更改的服务器下载资源。
三、离线本地存储和传统的浏览器缓存有什么不一样呢?
离线存储为整个web提供服务,浏览器缓存只缓存单个页面;
离线存储能够指定须要缓存的文件和哪些文件只能在线浏览,浏览器缓存没法指定;
离线存储能够动态通知用户进行更新。
四、如何实现

离线存储是经过manifest文件来管理的,须要服务器端的支持,不一样的服务器开启支持的方式也是不一样的。对于Tomcat须要修改 /conf/web.xml文件,添加以下MIMEType配置:

[html]  view plain copy
 
  1. <mime-mapping>  
  2.        <extension>manifest</extension>  
  3.        <mime-type>text/cache-manifest</mime-type>  
  4. </mime-mapping>  

注意,<extension>manifest</extension>中内容必须和manifest文件后缀名一致。

 

一个典型的manifest文件应该相似这样:

 

[html]  view plain copy
 
  1. CACHE MANIFEST//必须以这个开头  
  2. version 1.0 //最好定义版本,更新的时候只需修改版本号  
  3. CACHE:  
  4.     m.png  
  5.     test.js  
  6.     test.css  
  7. NETWORK:  
  8.     *  
  9. FALLBACK  
  10.     online.html offline.html  

其中CACHE指定须要缓存的文件;NETWORK指定只有经过联网才能浏览的文件,*表明除了在CACHE中的文件;FALLBACK每行分别指定在线和离线时使用的文件
要让manifest管理存储。

有了manifest文件后,还须要在html标签中定义manifest属性,以下:

[html]  view plain copy
 
  1. <!DOCTYPE html>  
  2. <html lang="en" manifest='test.manifest'>  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title></title>  
  6. </head>  
  7. <body>  
  8.     
  9. </body>  
  10. </html>  

五、经过JS动态控制更新
应用在离线后将保持缓存状态,除非发生如下某种状况:
用户清除了浏览器对您网站的数据存储。
清单文件通过修改。请注意:更新清单中列出的某个文件并不意味着浏览器会从新缓存该资源。清单文件自己必须进行更改。

缓存状态:
window.applicationCache 对象是对浏览器的应用缓存的编程访问方式。其 status 属性可用于查看缓存的当前状态:

[html]  view plain copy
 
  1. var appCache = window.applicationCache;  
  2. switch (appCache.status) {  
  3.   case appCache.UNCACHED: // UNCACHED == 0  
  4.     return 'UNCACHED';  
  5.     break;  
  6.   case appCache.IDLE: // IDLE == 1  
  7.     return 'IDLE';  
  8.     break;  
  9.   case appCache.CHECKING: // CHECKING == 2  
  10.     return 'CHECKING';  
  11.     break;  
  12.   case appCache.DOWNLOADING: // DOWNLOADING == 3  
  13.     return 'DOWNLOADING';  
  14.     break;  
  15.   case appCache.UPDATEREADY:  // UPDATEREADY == 4  
  16.     return 'UPDATEREADY';  
  17.     break;  
  18.   case appCache.OBSOLETE: // OBSOLETE == 5  
  19.     return 'OBSOLETE';  
  20.     break;  
  21.   default:  
  22.     return 'UKNOWN CACHE STATUS';  
  23.     break;  
  24. };  

要以编程方式更新缓存,请先调用 applicationCache.update()。此操做将尝试更新用户的缓存(前提是已更改清单文件)。最后,当applicationCache.status 处于 UPDATEREADY 状态时,调用 applicationCache.swapCache() 便可将原缓存换成新缓存。

 

[html]  view plain copy
 
  1. var appCache = window.applicationCache;  
  2. appCache.update(); // Attempt to update the user's cache.  
  3. ...  
  4. if (appCache.status == window.applicationCache.UPDATEREADY) {  
  5.   appCache.swapCache();  // The fetch was successful, swap in the new cache.  
  6. }  

 

请注意:以这种方式使用 update() 和 swapCache() 不会向用户提供更新的资源。此流程只是让浏览器检查是否有新的清单、下载指定的更新内容以及从新填充应用缓存。所以,还须要对网页进行两次从新加载才能向用户提供新的内容,其中第一次是得到新的应用缓存,第二次是刷新网页内容。

好消息是,您能够避免从新加载两次的麻烦。要使用户更新到最新版网站,可设置监听器,以监听网页加载时的 updateready 事件:

[html]  view plain copy
 
  1. //Check if a new cache is available on page load.  
  2. window.addEventListener('load', function(e) {  
  3.   window.applicationCache.addEventListener('updateready', function(e) {  
  4.     if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {  
  5.       // Browser downloaded a new app cache.  
  6.       // Swap it in and reload the page to get the new hotness.  
  7.       window.applicationCache.swapCache();  
  8.       if (confirm('A new version of this site is available. Load it?')) {  
  9.         window.location.reload();  
  10.       }  
  11.     } else {  
  12.       // Manifest didn't changed. Nothing new to server.  
  13.     }  
  14.   }, false);  
  15. }, false);  

六、APPCACHE 事件(详见W3C Spec:http://www.w3.org/TR/2012/WD-html5-20120329/offline.html#offline

 

Event name Interface Fired when... Next events
checking Event The user agent is checking for an update, or attempting to download the manifest for the first time. This is always the first event in the sequence. noupdatedownloading,obsoleteerror
noupdate Event The manifest hadn't changed. Last event in sequence.
downloading Event The user agent has found an update and is fetching it, or is downloading the resources listed by the manifest for the first time. progresserrorcached,updateready
progress ProgressEvent The user agent is downloading resources listed by the manifest. progresserrorcached,updateready
cached Event The resources listed in the manifest have been downloaded, and the application is now cached. Last event in sequence.
updateready Event The resources listed in the manifest have been newly redownloaded, and the script can use swapCache() to switch to the new cache. Last event in sequence.
obsolete Event The manifest was found to have become a 404 or 410 page, so the application cache is being deleted. Last event in sequence.
error Event The manifest was a 404 or 410 page, so the attempt to cache the application has been aborted. Last event in sequence.
The manifest hadn't changed, but the page referencing the manifest failed to download properly.
A fatal error occurred while fetching the resources listed in the manifest.
The manifest changed while the update was being run. The user agent will try fetching the files again momentarily.

经过对这些事件的监听处理能更好的控制应用程序文件的缓存、更新。

 

7.一个简单的离线缓存的应用
建一个web工程AppCache,包括四个文件:
appcache_offline.html

[html]  view plain copy
 
  1. <html manifest="clock.manifest">  
  2.   <head>  
  3.     <title>AppCache Test</title>  
  4.     <link rel="stylesheet" href="clock.css">  
  5.     <script src="clock.js"></script>  
  6.   </head>  
  7.   <body>  
  8.     <p><output id="clock"></output></p>  
  9.     <div id="log"></div>  
  10.   </body>  
  11. </html>  

clock.manifest

[html]  view plain copy
 
  1. CACHE MANIFEST  
  2. #VERSION 1.0  
  3. CACHE:  
  4. clock.css  
  5. clock.js  

clock.css

[html]  view plain copy
 
  1. output { font: 2em sans-serif; }  
[html]  view plain copy
 
  1. clock.js  
  2. setTimeout(function () {  
  3.     document.getElementById('clock').value = new Date();  
  4. }, 1000);  

联网状况下访问:http://localhost:8080/AppCache/appcache_offline.html,页面间断显示系统当前时间;断开网络后仍然能够正常访问。以下所示

相关文章
相关标签/搜索