本文将简要介绍如何用 Google Gears 提供的 API 增强您的 Web 应用程序,包括增加离线支持,提高运行速度和本地数据库支持等。
众所周知,Ajax 可以使得 Web 应用程序的响应速度提高一大块,然而云计算和 SaaS(Software as a Service) 的用户仍然期望获得更快的响应速度,那 Web 应用程序还能更快吗?答案是肯定的。随着硬件技术的不断升级,客户端计算机的计算能力逐步提高,如果 Web 应用程序可以充分利用闲置的客户端计算能力,那将进一步提高其响应速度,但如何充分利用客户端计算能力便成了开发者新的挑战, Google Gears 正是帮助 Web 应用程序开发者应对这种挑战的有力工具。其次,用户有时希望在离线的情况下也可以使用 Web 应用程序,这无形当中增加了 Web 应用程序开发者的痛苦指数, Google Gears 恰好可以减轻开发者在这方面的痛苦。最后,企业用户对于采纳云计算和 SaaS 总会存在一种顾虑,那就是企业的核心数据拱手交给第三方公司来存储和管理,这显然使得企业难以保护自己公司的商业机密 , 而 Google Gear 可以允许用户将 Web 应用程序产生的用户数据存储到用户自己的电脑中,而不是将数据存储到云端或者 SaaS 提供商的数据中心。本文将逐个介绍 Google Gears 提供的各种特性和 API,并且会提供使用这些 API 的例子。
Google Gears 是 Google 公司推出的一个开源项目,它是一个浏览器的插件,它会添加新的功能到浏览器,并暴露相应的 JavaScript API 给 Web 应用程序,以此增强 Web 应用程序的功能和性能。目前 Google Gears 支持 Firefox 1.5+, Internet Explorer 6.0+ 和 Safari 3.1.1+ 等主流浏览器。
首先, Google Gears 提供的 LocalServer API 可以将 Web 应用程序的 HTTP 资源缓存到用户的硬盘中,这样可以在 Ajax 的基础上进一步提高 Web 应用程序的响应速度,同时也使得用户在没有网络连接的情况下依然可以使用 Web 应用程序;其次, Google Gears 提供了 WorkerPool API 帮助 Web 应用程序在后台进行耗时的运算以提高 UI 的响应能力, Web 应用程序也可以用这种方式将原来由服务器承担的一部分运算工作交给客户端来处理;第三, Google Gears 提供的 Database API 则可以让 Web 应用程序将数据保存到用户的硬盘中并遵守同源安全策略,以此保护用户的敏感数据不被外露。除此之外, Google Gears 还提供了 Desktop, Geolocation 等 API 来丰富已有的功能。目前有 Google Docs, Google Reader 和 Zoho 等 Web 应用程序利用 Google Gears 来提供更多的功能。下面将介绍如何利用 Google Gears 提供的各种 API 来增强你的 Web 应用程序。
为 了开发 Google Gears 应用程序,你需要先安装 Google Gears 插件到你的浏览器,用你的浏览器访问 http://gears.google.com/,如果你的浏览器没有安装 Google Gears 插件,在显示的网页右上角会出现一个 Install Gears 的按钮,点击它将会开始安装 Google Gears。接下来你还需要到 http://code.google.com/intl/zh-CN/apis/gears/tools.html 下载 gears_init.js 文件,把该文件放到你的 Web 应用程序里面。由于 Google Gears 提供的 API 是基于 JavaScript 语言的,所以你不需要安装额外的 IDE 插件来开发 Google Gears 程序,仅需要普通的文本编辑器就可以。如果你的浏览器是 Firefox, 可以安装 Firebug 来调试 JavaScript。
只 有在浏览器安装了 Google Gears 插件的情况下,Google Gears 提供的 JavaScript API 才会生效,所以你的 Web 应用程序需要在一开始就检测用户的浏览器是否安装了 Google Gears, 如果没有就转到 Google Gears 的安装页面。清单 2 所示代码能够帮你做到这些
虽 然 Google Gears 不仅仅是为了给 Web 应用程序赋予离线功能而生,但离线功能却无疑是 Google Gears 最重要的使命之一。LocalServer, WorkerPool 和 Database 这三个 Gears 最早的,同时也是最核心的功能模块,为完成这一使命提供了必不可少的利器。
LocalServer 的主要功能是将 Web 应用程序的 HTTP 资源缓存到用户的本地硬盘中,并且当用户需要再次访问同样的网络资源的时候,对其进行拦截,转而用本地已存储的 HTTP 资源来代替服务器端的资源,为用户提供服务。这样,不但可以在 Ajax 的基础上进一步提高 Web 应用程序的响应速度,同时也使得用户在没有网络连接,或者网络连接状况不好的情况下依然可以像使用本地应用程序一样的流畅使用 Web 应用程序。
然 而,即使有了 LocalServer 的支持,也并不意味着我们需要一股脑的把所有的 Web 应用程序都拿到本地来执行,很多实时性很强,或者数据量过大的 Web 应用程序,都并不适合进行本地存储和利用本地资源来提供服务。因此,在利用 LocalServer API 对 Web 应用程序提供离线使用的功能之前,更重要的是要根据不同应用程序的应用场景,考量和分析哪些 Web 应用程序,或者某个 Web 应用程序的哪些功能和资源适合放到本地,并且能相对容易放到本地,放到本地之后能有更好的使用效果和用户体验。
在确定了要存储 Web 应用程序的哪些功能和资源之后,我们可以利用 LocalServer 提供的两种缓存方式来获取 HTTP 资源:
ResrouceStore – 获取指定 URL 的用户数据,PDF 文件,图片,样式表,JavaScript, 和 HTML 页面等。
在 使用包括 LocalServer API 在内的 Google Gears 的 API 之前,首先需要利用 Factory API 中的 create() 方法,指定需要用到的接口。正如清单 3 所示的代码,在调用 LocalServer API 的方法之前,需要先调用 create() 方法创建出一个 LocalServer 类型的对象。
var timerId = window.setInterval(function(){
// 一旦获得本地存储的版本信息,表明本地存储或更新已经结束。
if (store.currentVersion) {
window.clearInterval(timerId);
alert('Done! Current Version is ' +
store.currentVersion);
}
}, 500);
为 了让 Web 应用程序支持离线操作,首先需要解决的问题是将 Web 应用程序包含的 HTTP 资源缓存到用户本地的文件系统中,这个已经可以通过前面介绍的 LocalServer 来解决,第二个需要解决的问题是要让用户在使用 Web 应用程序的过程中产生的用户数据能够存放到本地,然后在连上网络的时候将本地的数据与服务器端的数据进行同步,这个问题可以用 Google Gears 提供的本地浏览器数据库来解决。之所以叫本地浏览器数据库,是因为数据库是运行在用户本地电脑上的,并且浏览器可以通过 JavaScript 操作该数据库。当然,本地浏览器数据库还可以用于存放用户希望保密的数据在用户自己的文件系统,而不是存放在云端。同时,即使在连上网络的情况下,也可以 通过访问本地数据带来性能上的巨大提升,毕竟这要比访问服务器端的数据快得多。
为了让浏览器上运行的 Web 应用程序能够操作本地浏览器数据库, Google Gears 提供了一套 Database API, 它使得 Web 应用程序可以将用户数据存放到用户自己的电脑中, Google Gears 是用开源的关系数据库系统 SQLite 作为这个本地浏览器数据库,当用户将 Google Gears 安装为浏览器的插件之后,用户实际上就把 SQLite 安装到了他 / 她的电脑中, Web 应用程序则可以调用 Google Gears 提供的 Database API 来操作 SQLite, Database API 允许开发人员在 JavaScript 里面直接用 SQL 语句从 SQLite 读取数据或者写入数据到 SQLite。在这一节我们将介绍如何调用 Database API 来操作 SQLite。
function create(){
// 如果在名为'testdb'的数据库中找不到表 emp, 就创建一个新表 emp
db.execute('create table if not exists emp' +
' (empno int, name text, age int, phone text)');
// 删除表 emp 中所有的数据
db.execute('delete from emp');
// 插入 3 条数据到表 emp
db.execute('insert into emp values (?, ?, ?, ?)', [111, 'Tony', 35, '1234567']);
db.execute('insert into emp values (?, ?, ?, ?)', [122, '傅飞', 31, '2345678']);
db.execute('insert into emp values (?, ?, ?, ?)', [135, 'Dave', 26, '3456789']);
}
function update(){
// 更新表 emp 的记录
db.execute('update emp set phone = ? where empno=?', ['88888888',122]);
db.execute('update emp set age = ? where empno=?', [28,135]);
query();
}
function query(){
// 查询表 emp 的所有记录,返回一个结果集对象
var rs = db.execute('select * from emp order by empno desc');
var con = document.getElementById("content");
con.innerHTML = "<ol>";
// 遍历结果集对象
while (rs.isValidRow()) {// 判断是否能调用 field() 等提取字段值的方法。
// 用 field(int fieldindex) 方法获取特定字段的值
con.innerHTML += "<li>"
+ rs.field(0)+", "
+ rs.field(1)+", "
+ rs.field(2)+", "
+ rs.field(3)+"</li>";
// 遍历下一条记录
rs.next();
}
con.innerHTML += "</ol>";
// 当遍历完结果集后记得调用 close 方法释放占用的资源
rs.close();
}
// 插入几条数据到表 movie
var sql = "insert into movie (name,director,stars) values (?, ?, ?)";
db.execute(sql, ['国产凌凌漆', '李力持', '周星驰 谷德昭 李力持']);
db.execute(sql, ['功夫', '周星驰', '周星驰 元华']);
db.execute(sql, ['The Dark Knight', 'Christopher Nolan', 'Heath Ledger']);
// 更新数据
var sql = 'update movie set stars = ? where name=?';
db.execute(sql, ['Heath Ledger,Christian Bale','The Dark Knight']);
db.execute(sql, ['周星驰 元华 冯小刚','功夫'])
// 删除表格
db.execute('drop table if exists movie');
// 检索数据
db.execute('select name,director,stars from movie order by name');
为了能够全文检索上面创建的表,你需要用 “< 表名 | 字段名 > match < 查询字符串 >” 作为检索条件。如果用表名,实际上是用表中隐含的跟表名同名的字段名,这将会检索表中所有类型为 Text 的字段;如果用字段名,这只在指定的字段上进行检索,这种情况并不是全文检索。我们这里用表名作为例子,假设表 movie 中已经有了如表 1 所示的记录,注意 Stars 字段中的人名是用空格隔开的,空格是 fts2 的分词符, fts2 全文检索的时候是按词来索引的,如果一个字段值没有包含一个空格,该字段值将被视为一个词。
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps API and Google Gear Geolocation API Example</title>
<script src="http://ditu.google.cn/maps?file=api&v=2&key=<your_map_api_key>"
type="text/javascript"></script>
<script type="text/javascript" src="gears_init.js"></script>
<script type="text/javascript">
// 创建 Geolocation 对象
var geo = google.gears.factory.create('beta.geolocation');
var map;
function updatePosition(p) {
alert('Current lat/lon is: ' + p.latitude + ',' + p.longitude);
// 在地图中显示用户当前位置
map.setCenter(new GLatLng(p.latitude,p.longitude),13);
}
function handleError(positionError) {
alert('Attempt to get location failed: ' + positionError.message);
}
function load() {// 初始化地图
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GSmallZoomControl());
map.addControl(new GScaleControl());
map.addControl(new GMapTypeControl());
map.addControl(new GOverviewMapControl());
map.setCenter(new GLatLng(39.617, 116.197), 13);
}
}
function gotoMyposition(){
// 获取用户当前位置
geo.getCurrentPosition(updatePosition, handleError);
}
</script>
</head>
<body onload="load()" onunload="GUnload()">
<h1>Hello,Google Maps API and Google Gears Geolocation API</h1>
<div id="map" style="width: 800px; height: 600px"></div>
<br/>
<input type="button" value="Go to my position" onClick="gotoMyposition()"/>
</body>
</html>
上面代码中的关键点是用 geo.getCurrentPosition(updatePosition, handleError) 来获取用户的当前位置,当 Google Gears 拿到用户的当前位置信息后,将其值传给 updatePosition 函数来处理,该函数调用 Google Maps API 将地图的中心位置设为用户的当前位置。如果 Google Gears 拿不到用户的当前位置,将会调用 handleError 函数来处理错误信息。
为 了保护用户的客户端,当 Google Gears 的 API 尝试访问本地资源的时候,浏览器会弹出一个许可对话框让用户选择是否允许该操作,当用户选择允许该操作的时候, Google Gears 会记住这个决定,以后同样的操作就不会再弹出许可对话框。但用户仍然可以更改被记住的决定,方法是在浏览器的菜单中选择“工具”->“Gears 设置”,在弹出的对话框中进行修改,如图 2 所示。