Lasciami fare uno scatto. Non ho mai usato backbone.js. Tuttavia, ho un fantastico wrapper IndexedDB YDB-DB e ho intenzione di supportare i framework di binding backbone.js e angular.js. Ma non sembra molto da fare.
Come suggerito da un interlocutore, il modello di adattatore di override Backbone.sync(method, model, options)
è possibile con poca logica aggiuntiva con la libreria del wrapper del database.
Backbone.sync
si aspetta che l'oggetto di ritorno sia l'oggetto jqXHR, che implementa Promise interface. Backbone.sync
è stato interrotto per intersecarsi per la memorizzazione nella cache nel database lato client. Un provider di origini dati, $.db
, imposta uno schema corrispondente al modello specificato. (Vedi il YDN-DB per maggiori dettagli.) Mi aspetto che il server backend accetti i dati del modello di Google GData (Atom Entry), in cui ogni modello ha un attributo etag e viene utilizzata una risoluzione ottimistica del conflitto.
$.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;
};
I metodi rimanenti possono essere implementati in modo simile. Le raccolte e le query possono anche intersecare e fornire dalla cache del database.
Se il server non implementa etag, è ancora funzionante, ma non si risparmia la larghezza di banda del server né si risolve il conflitto.
Molto interessante. L'app può essere utilizzata direttamente IndexedDB e lasciare che il wrapper IndexedDB si sincronizzi con il server. In caso di conflitto, il wrapper deve inviare l'evento aggiornato. Questo semplificherà ogni ruolo. –
@KyawTun grazie, questo sembra un buon design! Ma qualunque sia il design che mi viene in mente, avrei bisogno di backbone.js per comunicare con IndexedDB e il server remoto. La mia domanda è quale dei due modi menzionati nel mio post è il modo migliore per farlo. – shreyj