@MarcRochkind我想在你的书中添加一些知识以进行集成SQL.js https://github.com/kripken/sql.js/在 Chrome 应用程序中。
只需很少的努力就可以实现这一点(考虑到政策和规则的遵守)。
为了集成任何使用的东西eval
,您需要对脚本的特定部分进行沙箱处理。对于 SQL.js,它是整个库。
这可以通过需要在 main 中设置的 iframe 来完成.html
创建(或主)窗口所需的文档,例如chrome.app.window.create('index-app.html', { ..
主文档和 iframe 之间的通信基础将是使用发布消息 https://developer.chrome.com/extensions/messaging用于发送和接收消息。
假设这个 iframe 的来源叫做/iframes/sqljs-sandboxed.html
。
在里面manifest.json
你需要指定sqljs-sandboxed.html
作为沙箱。指定的沙箱可以运行eval
and eval
-like 结构如new Function
.
{
"manifest_version": 1,
"name": "SQL.js Test",
..
"sandbox": {
"pages": [
"iframes/sqljs-sandboxed.html",
]
}
}
The sqljs-sandboxed.html
使用事件侦听器对类型的事件做出反应message
。在这里,您可以简单地添加逻辑(为了简单起见,我使用了 switch 语句)来执行使用 SQL.js 构建的任何操作。
内容为sqljs-sandboxed.html
举个例子:
<script src="/vendor/kripken/sql.js"></script>
<script>
(function(window, undefined) {
// a test database
var db = new SQL.Database();
// create a table with some test values
sqlstr = "CREATE TABLE hello (a int, b char);";
sqlstr += "INSERT INTO hello VALUES (0, 'hello');";
sqlstr += "INSERT INTO hello VALUES (1, 'world');";
// run the query without returning anything
db.run(sqlstr);
// our event listener for message
window.addEventListener('message', function(event) {
var params = event.data.params,
data = event.data.data,
context = {};
try {
switch(params.cmd) {
case '/do/hello':
// process anything with sql.js
var result = db.exec("SELECT * FROM hello");
// set the response context
context = {
message: '/do/hello',
hash: params.hash,
response: result
};
// send a response to the source (parent document)
event.source.postMessage(context, event.origin);
// for simplicity, resend a response to see if event in
// 'index-app.html' gets triggered a second time (which it
// shouldn't)
setTimeout(function() {
event.source.postMessage(context, event.origin);
}, '1000');
break;
}
} catch(err) {
console.log(err);
}
});
})(window);
</script>
测试数据库仅创建一次,事件侦听器使用简单的开关镜像 API。这意味着为了使用 SQL.js,您需要针对 API 进行编写。乍一看,这可能有点不舒服,但从普通意义上讲,这个想法与实现 REST 服务是等效的,在我看来,从长远来看,这是非常舒服的。
为了发送请求,index-app.html
是发起者。需要指出的是,可以向 iframe 发出多个请求异步地。为了防止交叉冲突,状态参数以唯一标识符的形式随每个请求一起发送(在我的示例中是 unique-ish)。同时监听器被附加到message
过滤掉所需响应并触发其指定回调的事件,如果触发,则将其从事件堆栈中删除。
为了快速演示,创建了一个对象,该对象可以自动连接和分离message
事件。最终listen
函数最终应该过滤特定的字符串值,例如sandbox === 'sql.js'
(本例中未实现)为了加快许多滤波器的选择message
使用沙盒中的多个 iframe 时可能发生的事件(例如用于模板化的handlebars.js)。
var sqlRequest = function(request, data, callback) {
// generate unique message id
var hash = Math.random().toString(36).substr(2),
// you can id the iframe as wished
content_window = document.getElementById('sqljs-sandbox').contentWindow,
listen = function(event) {
// attach data to the callback to be used later
this.data = event.data;
// filter the correct response
if(hash === this.data.hash) {
// remove listener
window.removeEventListener('message', listen, false);
// execute callback
callback.call(this);
}
};
// add listener
window.addEventListener('message', listen, false);
// post a request to the sqljs iframe
content_window.postMessage({
params: {
cmd: request,
hash: hash
},
data: data
}, '*');
};
// wait for readiness to catch the iframes element
document.addEventListener('DOMContentLoaded', function() {
// faking sqljs-sandboxed.html to be ready with a timeout
setTimeout(function() {
new sqlRequest('/do/hello', {
allthedata: 'you need to pass'
}, function() {
console.log('response from sql.js');
console.log(this.data);
});
}, '1000');
});
为简单起见,我使用超时来防止在加载 iframe 之前发送请求。根据我的经验,最佳实践是让 iframe 向其父文档发布一条消息,表明 iframe 已加载,从这里开始您可以开始使用 SQL.js。
最后,在index-app.html
你指定 iframe
<iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>
内容在哪里index-app.html
可能
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>
<h1>Hello, let's code with SQL.js!</h1>
<script src="/assets/js/sqljs-request.js"></script>
</body>
</html>