清单 5. 对应的 manifest 文件
{ "betaManifestVersion": 1, "version": "1.0", "entries": [ { "url": "ManagedResourceStore.html"}, { "url": "gears_init.js"} ] } |
首先,将 HTML 页面和 manifest 文件部署到 HTTP 服务器上,之后我们便可以通过浏览器访问该页面。点击 "Create Managed Store" 按钮,会触发一个创建 ManagedResourceStore 类型的本地存储的事件,该事件会将 manifest 文件里列出的所有同源网络资源下载并存储到本地硬盘。如果你想知道它们被存储到了哪里,存放路径因操作系统和浏览器的不同而不同,具体的位置可以参看:
http://code.google.com/intl/zh-CN/apis/gears/api_database.html#directories接下来用户便可以通过访问与连网时相同的 URL,或者通过创建的桌面快捷方式(在后面的章节会提到如何为你的离线 Web 应用程序创建桌面快捷方式),在即使没有网络连接的情况下依然可以访问并使用这个页面。这时,如果我们更新了服务器端的资源文件,并且相应的更新了 manifest 文件中的版本信息,你会看到,存储到本地的网页信息,也会跟着自动被更新。当然,如果你等不及自动更新,也可以通过再次点击 "Create Managed Store" 按钮,调用 checkForUpdate() 方法手动更新页面。
![]() ![]() |
使用 WorkerPool API
在一个页面执行计算量比较大的任务或 I/O 操作时,Web 应用程序经常会慢到不响应,这个时候 WorkerPool 就有了用武之地。WorkerPool 可以用来在父页面的后台独立地执行计算量大的任务,而父页面则继续执行自己的任务。清单 6 演示了如何使用 WorkerPool API
清单 6. 使用 WorkerPool API
父页面代码
<html>
<head>
<title>Google Gears WorkerPool API</title>
<script type="text/javascript" src="gears_init.js"></script>
<script type="text/javascript">
// 父页面的 JavaScript 代码,也就是父 Worker
// 创建两个 workerPool 对象
var wp1 = google.gears.factory.create('beta.workerpool');
var wp2 = google.gears.factory.create('beta.workerpool');
function onMsg(a,b,message){
var msg = document.getElementById("msg");
msg.innerHTML = '收到的消息来自 worker '
+ message.sender + ',消息内容如下 : <br/>'
+ message.body;
}
// 设置当父 worker 收到消息时用 onMsg 方法来处理
wp1.onmessage = onMsg;
wp2.onmessage = onMsg;
function callWorker1(){
/* 创建一个子 Worker, 调用完 createWorkerFromUrl 方法后,
* 父 worker 和子 worker 将并行运行,当然子 worker 是在后台运行
*/
var childWorkerId = wp1.createWorkerFromUrl('worker.js');
// 父 worker 发送消息给子 worker
wp1.sendMessage(["Hello,", {"gears": "Google Gears!"}], childWorkerId);
}
function callWorker2(){
var childWorkerId = wp2.createWorkerFromUrl('worker.js');
wp2.sendMessage(["您好 ,", {"gears": "世界 !"}], childWorkerId);
}
</script>
</head>
<body>
<h1>Hello, WorkerPool API</h1>
<input type="button" value="WorkPool A Calls Child Worker"
onclick="callWorker1();">
<input type="button" value="WorkPool B Calls Child Worker"
onclick="callWorker2();"><hr/>
<div id="msg"></div>
</body>
</html>
worker.js 文件
(function(){
// 子 worker 可以在此执行计算量很大的代码
})();
var wp = google.gears.workerPool;
wp.onmessage = function(a, b, message) {
var reply = "This is reply message from child work:"
+ message.body[0]
+ message.body[1].gears;
wp.sendMessage(reply, message.sender);
}
|
WorkerPool 不是单例对象,所以可以看到在上面的父页面中可以创建两个 WorkerPool。在父页面的 Javascript 代码相当于父 worker, 你可以用 WorkerPool 对象的 createWorkerFromUrl() 方法创建一个子 worker, 该方法的参数是 JavaScript 文件的 URL, 也可以用 createWorker() 方法创建,参数是一段 JavaScript 代码。创建完子 worker 之后,父 worker 和子 worker 将并行运行 , 子 worker 在后台承担计算量大的任务,而父 worker 在前面继续响应处理用户操作。
另外,由于 WorkerPool 更像是一个进程池,而不是线程池,所以 worker 之间不共享执行状态,他们之间的相互通讯只能通过消息传递,也就是调用 WorkerPool 对象的 sendMessage() 方法,该方法有两个参数:
- 第一个参数是要传递的消息内容。
- 第二个参数是接受该消息的 worker 的 ID,WorkerPool 对象的两个方法 createWorkerFromUrl() 和 createWorker() 返回的就是创建的子 worker 的 ID, 可以用来作为该参数的值。
不管是父 worker 还是子 worker, 要想得到 sendMessage() 方法传过来的消息,都需要事先定义回调函数 onmessage,用于处理接收到的消息。
正是由于 WorkerPool 之间不共享执行状态,作为结果,子 worker 不能访问父页面的 DOM,以及 document, window 这样的对象,只有父 worker 能访问这些对象。如果子页面要访问这些对象,可以通过给父 worker 发消息让父 worker 来访问。但是,子 worker 还是能调用 JavaScript 的内置函数和大部分 Google Gears API。
![]() ![]() |
使用 Database API
为了让 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。
清单 7 所示代码演示了如何用 Database API
- 打开或创建一个新数据库
- 创建表
- 删除表中的记录
- 插入记录到表中
- 查询表中的数据以及遍历返回的结果集
- 更新表中的数据
- 删除表
清单 7. 使用 Database API 操作 SQLite 数据库
<html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <script type="text/javascript" src="gears_init.js"></script> <script type="text/javascript"> // 创建 Database 对象 var db = google.gears.factory.create('beta.database'); // 打开名为'testdb'的 SQLite 数据库,如果不存在,则创建它 db.open('testdb'); 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(); } function del(){ // 删除表 emp db.execute('drop table emp'); document.getElementById("content").innerHTML= ""; } </script> </head> <body> <h1>Hello,Database API</h1><hr/> <input type="button" value="Create table and populate rows" onClick="create()"/> <input type="button" value="Update" onClick="update()"/> <input type="button" value="Query" onClick="query()"/> <input type="button" value="Delete table" onClick="del()"/></br> <div id="content"></div><br/> </body> </html> |