0

インターネットで見つけたさまざまな例に従って、indexedDB を初めて試しています。多少は機能しますが、データベースを読み取ると一貫性のない結果が得られます。

データベースは次のように作成されます。

myapp.indexedDB.open = function() {
    var request = indexedDB.open('todos', "2");

    request.onblocked = function(e) {
        alert('Please close all other tabs with this site open so the database can be updated.');
    };

    request.onsuccess = function(e) {
        myapp.indexedDB.db = e.target.result;
        myapp.indexedDB.db.onversionchange = function(e) {
            myapp.indexedDB.db.close();
            alert('The database is being upgraded. Please reload.');
        };
        myapp.indexedDB.getAllTodoItems();
    };

    request.onupgradeneeded = function(e) {
        var db = e.target.result;

        if(!db.objectStoreNames.contains('todo')) {
            var store = e.currentTarget.result.createObjectStore(
                'todo',
                {keyPath: "timeStamp"}
            );
        }

        if(!db.objectStoreNames.contains('sites')) {
            var site_store = e.currentTarget.result.createObjectStore(
                'sites',
                {keyPath: 'id'}
            );
        }
    };
    request.onfailure = myapp.indexedDB.onerror;
};

todo ストアは、私が見つけた例からのものです。困っているのはサイトストアです。

サイトストアを次のように読みます。

function update_sites() {
    $('#sites_table').ig_grid('delete_all_rows');
    var db = myapp.indexedDB.db;
    var trans = db.transaction(["sites"], "readwrite");
    var store = trans.objectStore('sites');

    var cursorRequest = store.openCursor();

    cursorRequest.onsuccess = function(e) {
        var result = e.target.result;
        if(!!result == false) return;

        render_site(result.value);
        console.log('rendered a site');
        result.continue();
    };

    cursorRequest.onerror = myapp.indexedDB.onerror;
}

function render_site(site) {
    $('#sites_table').ig_grid('add_row', [site.id,site.id,site.flag,site.site_code,site.site_name,site.owner_name,site.address,site.hive_capacity,site.hive_count,render_status(site.status_id)]);
}

これまでのところ、すべて順調です。データベースに書き込まれたデータは正しく読み取られ、レンダリングされます。

データベースを更新すると問題が発生します。更新は次のように行われます。

function sync_sites() {
    display_status('');
    var jqxhr = $.ajax({
        type:   "GET",
        url:    '/myapp.pl/REST/sites'
    })
    .fail(function(jqXHR, textStatus) {
        display_status(jqXHR.responseText);
    })
    .done(function(data, textStatus, jqXHR) {
        var sites = jQuery.parseJSON(data.data);
        for (var i = 0; i < sites.length; i++) {
            myapp.indexedDB.add_site(sites[i]);
        }
        alert('sync done');
    });
}

myapp.indexedDB.add_site = function(site) {
    var db = myapp.indexedDB.db;
    var trans = db.transaction(["sites"], "readwrite");
    var store = trans.objectStore('sites');
    var request = store.put(site);

    request.onsuccess = function(e) {
        // TODO: whatever is appropriate if the site is added successfully
    };

    request.onerror = function(e) {
        console.log(e.value);
    };
};

データベースの更新も成功します。

問題は、データベースの更新が開始された直後、つまり「同期完了」アラートが表示された直後に、update_sites 関数が表示されたサイトのテーブルを空にし、サイトを追加しないことです: データベースが空であるかのように。次に、サイトの表示をリロードし続けると、さらに数秒 (数回リロード) した後、数百から数千の行がサイト テーブルに追加され、各行が数回複製されます。通常、サイトのストア/テーブルには実際には 216 のレコードがあります。最終的に、最後のデータベースの更新 (put) が完了する頃 (と思う) に、表示の更新が再び正しく機能するようになります。

表示更新 (update_sites) は、ほとんどの場合正しく機能します。sync_sites の実行後、数秒という短い間隔で実行すると、正しくない結果しか得られません。

2 つのエラー モードがあります。最初のモードでは、ストアからデータが読み取られず、ストアが空であるか、カーソルがレコードに一致しなかったかのように扱われます (成功したことはありません)。次に、ストア内のすべてのレコードが返された後もカーソルが停止せず、すべてのレコードを何度も繰り返しループし続け、最終的に一見任意のポイントで停止します。

update_sites が正しく実行されたとき、または誤った結果が返されたとき、または sync_sites からのいずれの場合でも、エラー コンソールにエラーは表示されません。実際、これが実行されているとき、エラー コンソールにエラーや警告はまったく表示されません。

基礎となるデータベースを sqlite3 で検査しましたが、データベースにレコードの重複はありません。object_data には 219 のレコードがあり、そのうち 3 つは todo ストアに関連し、216 は sites ストアに関連しています。

FWIW、これは Firefox 16.0.1 です。

私は何か間違ったことをしていますか?

エラーの原因を特定するのに役立つ、有効にできる追加のエラー、警告、トレース、または診断はありますか?

他の誰かがこの動作を見たことがありますか?

ありがとう、イアン

4

1 に答える 1

3

alert('sync done');IDBRequestonsuccessハンドラーが正常に追加されたことを意味しないため、 IndexedAPI の非同期の性質により、正しくありません。oncompeletedIDBTransaction のハンドラーのみが、それが追加され、レコードを照会する準備ができていることを確認します。

さらに、単一のトランザクションを使用してレコードを保存する必要があります。ループして一度にレコードを入れるようにするmyapp.indexedDB.add_site必要があります。コールバックを呼び出すmyapp.indexedDB.add_sites(sites, callback)とき。oncompeleted

編集: add_sites 関数を追加します。

myapp.indexedDB.add_sites = function(sites, callback) {
  var db = myapp.indexedDB.db;
  var trans = db.transaction(["sites"], "readwrite");
  trans.oncompleted = callback;
  var store = trans.objectStore('sites');

  var put = function(i) {
    var request = store.put(sites[i]);

    request.onsuccess = function(e) {
      i--;
      if (i >= 0) put(i);    
    };

    request.onerror = function(e) {
      console.log(e.value);
    };
  };

  put(sites.length - 1);
};
于 2012-10-22T23:18:51.743 に答える