与web开发中主要将数据保存在服务器端不同(cookie中仅保存极少量信息且会过期),数据持久化(Data Persistence)是本地应用开发中的常见需求,通俗的讲就是将瞬时数据(比如内存中的数据,断电即失效)保存为持久数据(比如写入数据库中长久保存); 由于NW.js的特性,可供选择的本地持久化方案非常丰富,既可以依赖于Node.js直接使用NeDB、LowDB等第三方数据库方案,也可以使用HTML5及其相关标准中提供的WebSQL、WebStorage、IndexedDB等方案,甚至直接将简单的数据保存到本地文件中
[I]. 直接存储数据到本地文件
正如之前的文章提到过的,NW.js提供了
App.dataPath
来访问系统的应用数据目录, 可以利用其方便的存储应用配置文件等
不同平台上的具体指向:
- Win: $LOCALAPPDATA%/
- Linux: ~/.config/
- Mac: ~/Library/Application Support/
var fs = require('fs');
var path = require('path');function saveSettings (settings, callback) {
var file = 'my-settings-file.json';
var filePath = path.join(nw.App.dataPath, file);
fs.writeFile(filePath, settings, function (err) {
if (err) {
console.warn(err.message);
return;
} else if (callback) {
callback();
}
});
}var mySettings = {
"language": "zh-CN",
"theme": "dark"
};saveSettings(mySettings, function () {
console.log('Settings saved');
});
[II]. Web storage
Web storage 是浏览器中最简单的一种数据存储技术,可以暂时或永久的保存 key-value 数据;适合于简单且非密集的数据事务场景
2.1 基本规则
- 每个domain最多5MB的存储限制
- 同步调用,有可能阻塞主渲染进程
- 直接读写磁盘,可能影响性能
- 没有高级的索引和查询等
- 只能用字符串存取数据,复杂数据和图片应分别用JSON和base64转码后存储
- 可以在 DevTools->Application->Storage->Local Storage 标签页中查看已存储的数据
2.2 操作方法
代码语言:javascript复制//存数据
localStorage.setItem('myKey', myValue);//取数据, 无结果返回null
localStorage.getItem('myKey');
localStorage.myKey;
localStorage['myKey'];//删数据
localStorage.removeItem('myKey');
delete localStorage.myKey;
localStorage.clear();//存储数据时会触发事件(可用于监听其他页面是否修改了某个数据)
window.addEventListener('storage' e=>console.log(e.key, e.newValue));
2.3 基于localStorage的StoreDB
代码语言:javascript复制StoreDB(https://github.com/djyde/StoreDB) 是一个基于localStorage的本地储存库,通过模拟MongoDB的一些API和概念(如“集(collection)”和“文档(document)”),使你能使用 localStorage 储存复杂数据
//插入数据
storedb('players').insert({
"name":"Randy",
"sex":"male",
"score":20
},function(err,result){
if(!err){
//do sth...
} else //do sth...
})//更新数据
storedb('players').update(
{"name":"Randy"},
{"$inc":{"score":"10"}
},function(err){
if(!err){
//do sth...
} else //do sth...
})//查找数据
storedb('players').find({
"name":"Randy"
},function(err,result){
if(!err){
//use result to do sth...
} else //do sth...
})
[III]. Web SQL 数据库
- Web SQL 是一个基于 SQLite 的数据库规范,使得在浏览器端使用 SQL 语言(如select, insert, update, delete, joins, inner selects等)变得简便易行 --- 这也是其最大的优点
- Web SQL Database API 实际上未包含在 HTML 5 规范之中,它是一个独立的规范
- 其 API 有同步的,也有异步的, 同步版本的 API 只在工作线程(Worker Threads)上有用,由于并不是所有的浏览器都支持工作线程,一般情况下,都会使用异步 API
- 基本没有容量限制
- 虽然 W3C 官方已经声明不再维护 Web SQL Database 规范,但由于其广泛的实现程度,了解这些 API 对 Web 开发还是非常有必要的
3.1 基本概念
- SQL语句(SQL statement): 一条SQL查询语句
- 事务(transaction): 管理并顺序执行若干条SQL语句的容器,可以嵌套
- 错误回调:每条 SQL statement 及其所处的 transaction 都有各自的错误回调,用于精细或集约的捕获错误并引发回滚
- 回滚(roll back):错误发生时撤销单条语句或整个事务的操作
- 可以在 DevTools->Application->Storage->Web SQL 标签页中查看已存储的数据
3.2 常用方法
openDatabase()
: 新建数据库对象或打开已有的transaction()
: 执行一个事务并在错误发生时回滚executeSql()
: 执行SQL语句
//初始化一个数据库
var db = openDatabase(
'myDB', //数据库名
'1.0', //版本号
'My Database', //显示名
2 * 1024 * 1024, //容量
db=> console.log() //成功回调
);//执行一个事务
db.transaction(t=>{
//创建表
let sql1 = "CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY, title TEXT, content TEXT)";
t.executeSql(sql1);
//插入一条数据
let data1 = ['标题1', '内容1'];
let sql2 = "INSERT INTO articles(title, content) VALUES (?, ?)";
t.executeSql(sql2, data1);
//取数据
db.transaction(t=>{
t.executeSql(
"SELECT * FROM articles",
[],
(transaction, resultSet)=> {
let
data = []
,row
,rowNum = resultSet.rows.length
;
for (let i = 0; i<rowNum; i ) {
row = resultSet.rows.item(i);
data.push(row);
}
console.log(data);
}
);
});
//向一个假定并不存在的表里插入数据,引发错误
t.executeSql(
"INSERT INTO logs(message) VALUES (?)",
["我是一条日志"],
function sqlStatementCallback(transaction, resultSet) {},
function sqlStatementErrorCallback(transaction, err) {
//处理err
//该条语句被回滚,如果有后续语句继续执行
return false; //如果返回true,则会传递到事务的errorCallback
//,并引发整个事务的回滚
}
);
}, sqlError=> {
console.warn(sqlError.message);
});
[IV]. IndexedDB
- 存储 key-value 数据的事务型 NoSQL 非关系型数据库系统
- 可以存储复杂的javascript对象,并用一个或多个索引查询
- 基本没有容量限制
- 所有操作都是异步的
4.1 基本概念
- 数据库: 由
indexedDB.open(name, ver)
方法打开,返回一个IDBDatabase
接口格式的异步请求对象 ObjectStore
: 相当于关系型数据库中的数据库表table,实现IDBObjectStore
接口- 事务(transaction): 所有ObjectStore的读写操作都借由事务完成
- 可以在 DevTools->Application->Storage->IndexedDB 标签页中查看已存储的数据
4.2 代码示例
代码语言:javascript复制var
dbName = 'DBName'
,dbVer = 1
,openDbRequest = indexedDB.deleteDatabase(dbName) && indexedDB.open(dbName, dbVer)
;
openDbRequest.onerror = e=>console.warn(e);
openDbRequest.onsuccess = e=>{
let db = e.target.result;
console.log('数据库建立成功:', db.version);
};
openDbRequest.onupgradeneeded = e=> {
let db = e.target.result;
console.log(e); let
storeName = 'personsStore'
,storeOptions = {
keyPath: 'id',
autoIncrement: true
}
; // if (db.objectStoreNames.contains(storeName)) {
// console.log('删除了旧数据库');
// db.deleteObjectStore(storeName);
// }
let store = db.createObjectStore(storeName, storeOptions);
store.createIndex('by_name', 'name', {unique: false});
store.createIndex('by_age', 'age', {unique: false}); setTimeout(function() {
let
ts = db.transaction(['personsStore'], 'readwrite')
,persons = ts.objectStore('personsStore')
;
persons.add({
name: '小红',
age: 30
});
persons.add({
name: '小明',
age: 28
}).onsuccess = function() {
var key = this.result;
alert(key); persons.index('by_age').getAll().onsuccess =
e=>console.log('index by_age', e.target.result);
persons.get(key).onsuccess =
e=>console.log('get 2', e.target.result);
};
}, 2000);
};
4.3 完整接口文档
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
4.4 第三方封装实现
- Dexie: http://dexie.org/
var db = new Dexie("friend_database");
db.version(1).stores({
friends: 'name,shoeSize'
});
db.friends.put({name: "Nicolas", shoeSize: 8}).then (function(){
return db.friends.get('Nicolas');
}).then(function (friend) {
alert ("Nicolas has shoe size " friend.shoeSize);
}).catch(function(error) {
alert ("Ooops: " error);
});
- PouchDB: https://pouchdb.com/
db.get('mittens').then(function (doc) {
// okay, doc contains our document
}).catch(function (err) {
// oh noes! we got an error
});
db.allDocs({include_docs: true}).then(res => {
console.log(JSON.stringify(res))
});
db.get('mittens').then(function (doc) {
return db.remove(doc);
});
- https://github.com/nwjs/nw.js/wiki/Save-persistent-data-in-app
- http://www.ccydesign.com/websql-amd-indexdb/
- https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API
- https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDBAPI/UsingIndexedDB
- http://www.ibm.com/developerworks/library/wa-indexeddb/index.html
- http://blog.csdn.net/cainiaokan/article/details/29366105
- https://www.w3.org/TR/IndexedDB/#dfn-multientry
- http://web.jobbole.com/81793/
- http://www.csdn.net/article/2012-10-12/2810660-NoSQL-MongoDB-HBase
- http://baike.baidu.com/item/NoSQL
- http://www.cnblogs.com/xiaowei0705/archive/2011/04/19/2021372.html
- http://www.cnblogs.com/dolphinX/p/3415761.html
* 原创文章转载请注明出处