0

我是第一次尝试 indexedDB,尝试按照我在 Internet 上找到的各种示例进行操作。它在某种程度上有效,但是当我读取数据库时,我得到的结果不一致。

数据库创建如下:

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;
};

待办事项商店来自我找到的一个示例。这是我遇到困难的网站商店。

我像这样阅读网站商店:

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 条记录。最终,大约在最后一次数据库更新(放置)完成(我认为)显示更新再次正常工作的时候。

显示更新 (update_sites) 大部分时间都能正常工作 - 如果我在 sync_sites 运行后的几秒钟内运行它,它只会给出不正确的结果。

有两种错误模式:第一种,没有从存储中读取数据,好像它是空的或游标匹配没有记录(从未成功);并且在第二个中,在返回存储中的所有记录后,游标不会停止,它会一遍又一遍地循环遍历所有记录,直到最终在某个看似任意的点停止。

我在错误控制台中看不到任何错误,无论是 update_sites 正确运行还是给出不正确的结果,还是来自 sync_sites。事实上,当它运行时,错误控制台中根本没有错误或警告。

我已经用 sqlite3 检查了底层数据库,并且我可以看到数据库中没有重复的记录。object_data 中有 219 条记录:3 条与 todo 存储相关,216 条与站点存储相关。

FWIW,这是使用 Firefox 16.0.1。

难道我做错了什么?

是否有我可以启用的其他错误、警告、跟踪或诊断可能有助于查明错误原因?

有没有其他人看到过这种行为?

谢谢,伊恩

4

1 回答 1

3

由于 IndexedAPI 的异步性质alert('sync done');不正确,因为 IDBRequestonsuccess处理程序并不意味着它已成功添加。只有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 回答