我正在开发一个支持离线的网络应用程序。我将 Backbone.js 用于客户端代码。我需要backbone.js根据用户的在线/离线状态在远程服务器和本地IndexedDB之间切换。以下哪种方法是正确的方法:
- 通过 superfeedr使用这个indexeddb-backbone 适配器。但我觉得它更适合离线存储,而不是离线和在线。
- 覆盖backbone.js 中的sync() 方法,从而创建您自己需要的特定适配器。
我正在开发一个支持离线的网络应用程序。我将 Backbone.js 用于客户端代码。我需要backbone.js根据用户的在线/离线状态在远程服务器和本地IndexedDB之间切换。以下哪种方法是正确的方法:
让我试一试。我从来没有使用过backbone.js。但是,我有很棒的 IndexedDB 包装器YDB-DB,我计划支持backbone.js 和 angular.js 绑定框架。但似乎没什么可做的。
Backbone.sync(method, model, options)
正如提问者所建议的那样,使用数据库包装器库几乎不需要额外的逻辑,就可以覆盖适配器模式。
Backbone.sync
期望返回对象是 jqXHR 对象,它实现了Promise 接口。Backbone.sync
被覆盖以相交以在客户端数据库中缓存。数据源提供者$.db
被设置为与给定模型相对应的模式。(有关更多详细信息,请参阅 YDN-DB。)我希望后端服务器接受类似于 Google GData 的模型数据(Atom 条目),其中每个模型都有 etag 属性并使用乐观的冲突解决方案。
$.db = new ydn.db.Storage('db_name', schema);
var Backbone_sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
var df = $.Deferred();
if (method == 'read') {
var df_db = $.db.get(model.name, model.cid);
df_db.done(function(data) {
if (data) {
df.resolve(data);
options['header'].push({'If-Not-Match': data.etag});
var ajax_df = Backbone_sync(method, model, options);
ajax_df.done(function(new_data) {
if (new_data) {
assert(new_data.cid == model.cid);
$.db.put(model.name, new_data);
model.set(new_data).change();
} // else, no change
});
} else {
var ajax_df = Backbone_sync(method, model, options);
df.pipe(ajax_df);
ajax_df.done(function(new_data) {
$.db.put(model.name, new_data);
});
}
});
df_db.fail(function(e) {
throw e; // db connection blocking, or schema mismatch
});
} else if (method == 'update') {
options['header'].push({'If-Match': model.etag});
var ajax_df = Backbone_sync(method, model, options);
df.pipe(ajax_df);
ajax_df.done(function(new_data, status) {
if (status == 409) { // conflict
assert(new_data.cid == model.cid);
$.db.run(function(db) { // run in transaction
db.get(model.name, model.cid).done(function(data) { // NOTE: not $.db
if (data) {
var resolved_data = $.magic.resolve(new_data, data);
db.put(model.name, resolved_data);
model.set(resolved_data);
model.save(); // send merge result to server
} else {
db.put(model.name, new_data);
}
});
}, model.name, 'readwrite'); // transaction scope of model object store for read write operations
} else if (status == 404) { // not found
$db.clear(model.name, model.cid);
} else if (status < 300) {
assert(new_data.cid == model.cid);
$.db.put(model.name, new_data);
}
});
}
return df;
};
其余方法可以类似的方式实现。集合和查询也可以相交并从数据库缓存中提供。
如果服务器没有实现etag,它仍然可以工作,但是你不会节省服务器带宽,也不会解决冲突。