6

オフライン対応の Web アプリを使用しています。クライアント コードに Backbone.js を使用しています。ユーザーのオンライン/オフライン状態に応じて、リモート サーバーとローカルの IndexedDB を切り替える backbone.js が必要です。これを行う正しい方法は次のうちどれですか。

  1. このindexeddb-backbone アダプターを superfeedr で使用します。しかし、オフラインとオンラインの両方ではなく、オフライン ストレージのみに対応していると思います。
  2. backbone.js の sync() メソッドをオーバーライドして、独自のニーズ固有のアダプターを作成します。
4

1 に答える 1

5

撃ってみましょう。backbone.js を使用したことがありません。しかし、私は素晴らしい IndexedDB ラッパーYDB-DBを持っており、backbone.js および angular.js バインディング フレームワークをサポートする予定です。しかし、あまりすることはないようです。

質問者が示唆したように、オーバーライドのアダプター パターンはBackbone.sync(method, model, options)、データベース ラッパー ライブラリを使用した追加ロジックをほとんど使用せずに可能です。

Backbone.sync戻りオブジェクトは、 Promise インターフェイスを実装する jqXHR オブジェクトであると予想されます。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 を実装していない場合でも機能しますが、サーバーの帯域幅を節約したり、競合を解決したりすることはできません。

于 2012-10-06T10:00:55.193 に答える