HTML5离线存储

HTML5离线存储简介

离线存储 (Offline Storage) 是 HTML 5 规范中重要的一项特性,实现了 HTML 5 离线存储规范的浏览器将支持开发人员把客户端的某些资源缓存在浏览器中,也支持开发人员将数据直接保存在用户本地,以实现在没有网络连接的情况仍然可以使用 Web 应用程序。

缓存

浏览器的缓存由来已久,一般现代浏览器都有默认缓存 Web 静态页面、图片、样式表等文件的设置,以保证用户下次重新打开该页面时能有较快的响应速度。但是这些都是浏览器自身的实现,HTML 5 将该缓存机制规范化并定义了一系列的方法让开发人员可以自由的指定哪些资源需要由浏览器来做缓存。开发人员可以通过一个 manifest 文件来将需要缓存的文件名放入其中。

本地存储

HTML 5 本地存储引入了两种存储方式,DOM Storage 和 Web SQL,这里简单介绍一下 DOM Storage,然后将重点解释 Web SQL 的工作机制以及如何应用它。

DOM Storage

DOM Storage 又分为 localStorage 和 sessionStorage 两种。他们都是以 key/value 的形式来保存用户的数据。不同的是,sessionStorage 将保存与当前浏览器窗口相关的数据,当前窗口一旦关闭,sessionStorage 里的数据也就失效了。而 localStorage 则不同,在其中保存的数据将会长期有效,所有浏览器窗口都可以共享。当然,各个浏览器对本地存储的数据的大小限制是不一样的。

Web SQL 

Web SQL 实际上是将服务器端使用 SQL 语句操纵数据库的能力扩展到了浏览器端。它允许开发人员在客户端将比较复杂的数据通过一些基本的 SQL 语句保存在浏览器自带数据库中。这些 SQL 语句可以直接在 JavaScript 语言中编写运行,并且带有基本的数据库事务性的支持。

创建或者打开数据库

实现 HTML 5 Web SQL 的浏览器中将会支持 native 的 openDatabase 方法,如下清单所示是创建一个新的数据库的代码:


创建数据库
 function initDB(){  var myDB = null;     try {         if (!window.openDatabase) {             // 当前浏览器没有数据库支持            alert('db not supported');         } else {             var shortName = 'testdb';             var version = '1.0';             var displayName = 'test offline database';             var maxSize = 65536; // 字节            myDB = openDatabase(shortName, version, displayName, maxSize);         }     } catch(e) {         // 这里开始异常处理 .         if (e == INVALID_STATE_ERR) {             // 数据库版本异常 .             alert("Invalid database version.");         } else {             alert("Unknown error "+e+".");         }     }     // 返回创建好的数据库实例    return myDB;  } 

创建表

创建完数据库,紧接着我们在该数据库中创建一个表,创建表的语法与一般的 SQL 有少许差别,清单所示是创建一个表的代码:


创建表
 function createTables(db){  db.transaction(  function (transaction) {  transaction.executeSql('CREATE TABLE IF NOT EXISTS User(name TEXT, age INTEGER);',    [], function(result){}, function(tx,error){});  }  );  } 

从上述示例可以看出,所有 SQL 语句的执行都被嵌套在一个事务中,从而保证了数据的完整性和一致性。执行该 SQL 语句的结果以及错误处理需要在 executeSql 函数的最后两个参数中指定。

执行 SQL 语句

下面我们来具体看一下针对上面我们的代码创建出的数据库表如何做 CRUD 的操作。


执行插入语句
 db.transaction(  function (transaction) {  transaction.executeSql('INSERT INTO User values(?,?)',[“Mark”, 60],  function(result){}, function(tx,error){});  }) 


执行查询语句
 db.transaction(  function (transaction) {  transaction.executeSql('SELECT * FROM User WHERE name=?', [name],  function(result){}, function(tx,error){});  }) 


执行删除语句
 db.transaction(  function (transaction) {  transaction.executeSql('DELETE FROM User where name=?',[name],  function(result){}, function(tx,error){});  }); 

所有的 SQL 操作都需要在指定的函数中做结果处理以及错误处理,而且传统的 SQL 语句写起来也比较费事,这个时候我们都无比怀念 Java 语言中的 ORM 工具。所幸的是开发社区从来不缺有创意的开发人员,目前已经有不少的开源 Web SQL ORM 工具出现了,下面将会介绍一款比较成熟的 JavaScript 框架 persistence.js,看它是如何实现 ORM 的。

persistence.js 是一个 JavaScript 框架,最初它的设计目标是对 HTML Web SQL 进行 OR Mapping,以方便客户端开发人员进行快速的 Web SQL 访问。后来随着该框架的发展,它开始逐渐剥离了对数据库的依赖,成为一个可以支持各种数据库的框架。并且目前最新的版本也可以和服务器端框架,比如 Nodejs,RingoJS 一起工作。

获得persistence.js 

在 persistence.js 的 官网上可以得到所有的源代码。如图 1 所示:



图 1. 源代码 

目前 persistence.js 支持的浏览器包括:

  • 基于 webkit 的浏览器 (如 Google Chrome, Safari)
  • Firefox (Firefox 本身尚未支持 Web SQL API,这里是通过非 SQL 的方式来实现存储)
  • Opera
  • Android 浏览器 (1.6 and 2.x 上测试通过)
  • iPhone 浏览器 (iPhone OS 3+)
  • Palm WebOS (1.4.0)


引入 persistence.js

首先在 HTML 文件中加入对 persistence.js 的 JavaScript 文件的引用,这里我们只使用最基本的核心功能来演示它的 ORM 能力。



 <script type="text/javascript" src="js/persistence.js"></script>  <script type="text/javascript" src="js/persistence.store.sql.js"></script>  <script type="text/javascript" src="js/persistence.store.websql.js"></script>  <script type="text/javascript" src="js/persistence.store.memory.js"></script> 

persistence.js 将其核心模块分割成各个较小的 JavaScript 文件,有效的保证了高性能的加载,用户仅需要在用到某个功能模块时才引入相应的 JavaScript 文件。这里我们用到了 persistence.js,persistence.store.sql.js 和 persistence.store.websql.js,这三个文件是使用 Web SQL 必需的。如果用户想以在内存中临时保存数据的方式作为浏览器不支持 Web SQL API 时的替代,那么也可以将 persistence.store.memory.js 引入进来。

配置

在编写 ORM 的 JavaScript 代码前,我们需要告知 persistence.js 我们将会创建什么数据库或者连接向哪个已有的数据库。如清单 7 所示。而这段代码正对应了在清单 1 中描述的连接一个数据库的代码。由此可见 persistence.js 简化了大量的 JavaScript 代码。



 if (window.openDatabase) {  persistence.store.websql.config(persistence, 'testdb',         'My SQLite database', 5 * 1024 * 1024);  } else {  persistence.store.memory.config(persistence);  } 

persistence 是引入 persistence.js 后的一个全局变量。当前浏览器如果有 openDatabase API 存在,那么表示是支持 Web SQL 的,我们可以直接指定即将创建的数据库信息,如果没有,那么将使用另一种方式做存储。

创建表

数据库创建好后,我们接着就来看看如何用面向对象的方式创建一个表,清单 8 完成的功能将会如清单 2 所示的 SQL 语句。



 var User = persistence.define('User', {  name: "TEXT",  age: "INTEGER" });  persistence.schemaSync(); 

非常简洁的定义了一个 User 对象,再通过 schemaSync() 方法,数据库中对应的一个表就创建完成了。以后用户如果想对 User 表的数据做一些操作,直接从 User 对象调用相关的 API 就可以。

persistence.js 对基本的 SQLite 数据类型,如 NULL,INTEGER,REAL,TEXT,BLOB,是完全支持的,而且还有一些扩展类型也可以支持,如 INT,BOOL,DATE,JSON。

插入和删除数据

对 User 表插入一条记录就是直接将一个 User 对象保存起来,并调用 flush() 方法在持久化,如下。



 var mark = new User({name: "Mark", age: 60});  persistence.add(mark);  persistence.flush(); 

删除一条记录就是直接将一个 User 对象删除,如清单 10。


 persistence.remove(mark);  persistence.flush(); 

对表之间关联的支持

传统的数据库支持一对多,多对一,多对多的表间关联,这部分功能在很多 Java ORM 工具中已经很好的支持了,在 persistence.js 中,也能发现类似的实现。比如上例中的 User 表,我们需要加入一个新的 Address 表记录 User 对象的地址,每个 User 对象可能有多个地址。我们可以通过清单 11 轻易实现表的关联。



 var Address = persistence.define('Address', {  detail: "TEXT",  zipcode: "TEXT" });  User.hasMany(“addresses”, Address, “user”);  persistence.schemaSync();  var addr1 = new Address({detail:”addr1”, zipcode:”code1”});  var addr2 = new Address({detail:”addr2”, zipcode:”code2”});  persistence.add(addr1);  persistence.add(addr2);  mark.addresses.add(addr1);  mark.addresses.add(addr2);  persistence.flush(); 

hasMany() 方法是每个通过 persistence.define 定义出的对象都有的内置方法,通过执行上述 hasMany() 方法,User 表将会增加一个属性 addresses 作为与 Address 表的关联,并且 addresses 可以关联到多个 Address 对象。而 Address 对象也会增加一个 user 属性,通过 user 属性将某个 Address 对象关联到一个 User 对象。

类似的,用户也可以调用表对象的 hasOne() 方法来定义 Address 对象仅关联到一个 User 对象。

查询数据

persistence.js 提供了简单而强大的查询语法,查询数据是仅需要相当直观的一两次 API 调用。针对某个表的查询入口实际上就是从 persistence.define 定义出的对象入手。以上文定义的 User 为例。

User.all() 将会直接返回一个 QueryCollection,里面将包含所有的 User 对象。

User.load() 可以根据用户传入的 User 对象 ID 来加载某个 User 对象。

User.findBy() 可以根据用户传入的 User 对象属性以及属性的值来查询出符合条件的 User 对象集合并返回。

下面是一些运用上述 API 进行查询的示例。



 User.all().one(function(user){  console.log(user);  console.log(user.name);  console.log(user.addresses);  document.getElementById("demoReply").innerHTML = user.name;  }); // 查询出第一个 User 对象 User.load("6C22FD66801C41728AE5A6BCE0A8EE54", function(user){  console.log(user.name);  }); // 查询出 ID 为"6C22FD66801C41728AE5A6BCE0A8EE54"的 User 对象 User.findBy("name", "Mark", function(user){  console.log(user.age);  }); // 查询出 name 是 Mark 的 User 对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值