0

我在我正在构建的针对 iOS、Android 和 Windows 手机的移动应用程序上使用 Lawnchair.js。我的问题是我有一个相对简单的函数(见下文),它从对象中读取数据并将其保存在 indexeddb 数据库中。大约有 4MB 的数据,当我在 Internet Explorer 中检查时(通过 Internet 选项),第一次运行时,我可以看到数据库大约是 7MB。如果我重新加载页面并使用相同的数据重新运行相同的功能,它会增加到 14MB,然后是 20MB。我使用相同的键,所以我的理解是这应该只是更新记录,但几乎就像每次都插入所有新记录一样。我在使用 websql 适配器的移动 safari 上使用 Lawnchair 也有类似的行为。有没有人见过这个或有任何关于为什么会这样的建议?

以下代码来自我用来填充数据库的函数。

populateDatabase: function(database,callback) {
    'use strict';
    var key;
    try {
      for(key in MasterData){
        if(MasterData.hasOwnProperty(key)){
          var itemInfo = DataConfig.checkForDataUpdates[DataConfig.keyMap[key]];
          database.save({key:itemInfo["name"],hash:itemInfo["version"],url:itemInfo["url"],data:MasterData[key]});
        }
      }
      callback(true);
    } catch(e){
      callback(false);
    }
}

MasterData 是大型数据文件,itemInfo 包含键名、稍后用于检查 api 更新的哈希值以及更新位置的相对 url。创建数据库后,我将其传递给此函数,然后如果插入成功则返回 true,否则返回 false。

如前所述,我在 iOS 中看到了类似的问题,调用 database.save() 分配了大量内存但没有释放它,如果它填充数据库然后尝试更新一些记录,最终会导致崩溃。从等式中删除 Lawnchair 可以防止它崩溃,但在保存数据时它仍然分配大量内存。不确定这对于移动设备上的持久存储是否正常,Lawnchair 中的错误,或者我是一个菜鸟并且做了一些非常错误的事情,但我可以使用一些指针以及为什么 indexeddb 在每次保存时都会变得越来越大(至少在 IE10 的初始测试期间)??

编辑:索引数据库适配器的源代码在这里: https ://github.com/brianleroux/lawnchair/blob/master/src/adapters/indexed-db.js

这是我正在使用的保存功能的代码:

save:function(obj, callback) {
    var self = this;
    if(!this.store) {
        this.waiting.push(function() {
            this.save(obj, callback);
        });
        return;
     }

     var objs = (this.isArray(obj) ? obj : [obj]).map(function(o){if(!o.key) { o.key = self.uuid()} return o})

     var win  = function (e) {
       if (callback) { self.lambda(callback).call(self, self.isArray(obj) ? objs : objs[0] ) }
     };

     var trans = this.db.transaction(this.record, READ_WRITE);
     var store = trans.objectStore(this.record);

     for (var i = 0; i < objs.length; i++) {
      var o = objs[i];
      store.put(o, o.key);
     }
     store.transaction.oncomplete = win;
     store.transaction.onabort = fail;

     return this;
},

创建新实例时,Lawnchair 使用 indexed-db 适配器中的 init 函数,如下所示。

init:function(options, callback) {
    this.idb = getIDB();
    this.waiting = [];
    this.useAutoIncrement = useAutoIncrement();
    var request = this.idb.open(this.name, STORE_VERSION);
    var self = this;
    var cb = self.fn(self.name, callback);
    if (cb && typeof cb != 'function') throw 'callback not valid';
    var win = function() {
        // manually clean up event handlers on request; this helps on chrome
        request.onupgradeneeded = request.onsuccess = request.error = null;
        if(cb) return cb.call(self, self);
    };

    var upgrade = function(from, to) {
        // don't try to migrate dbs, just recreate
        try {
            self.db.deleteObjectStore('teststore'); // old adapter
        } catch (e1) { /* ignore */ }
        try {
            self.db.deleteObjectStore(self.record);
        } catch (e2) { /* ignore */ }

        // ok, create object store.
        var params = {};
        if (self.useAutoIncrement) { params.autoIncrement = true; }
        self.db.createObjectStore(self.record, params);
        self.store = true;
    };
    request.onupgradeneeded = function(event) {
        self.db = request.result;
        self.transaction = request.transaction;
        upgrade(event.oldVersion, event.newVersion);
        // will end up in onsuccess callback
    };
    request.onsuccess = function(event) {
       self.db = event.target.result; 

        if(self.db.version != (''+STORE_VERSION)) {
          // DEPRECATED API: modern implementations will fire the
          // upgradeneeded event instead.
          var oldVersion = self.db.version;
          var setVrequest = self.db.setVersion(''+STORE_VERSION);
          // onsuccess is the only place we can create Object Stores
          setVrequest.onsuccess = function(event) {
              var transaction = setVrequest.result;
              setVrequest.onsuccess = setVrequest.onerror = null;
              // can't upgrade w/o versionchange transaction.
              upgrade(oldVersion, STORE_VERSION);
              transaction.oncomplete = function() {
                  for (var i = 0; i < self.waiting.length; i++) {
                      self.waiting[i].call(self);
                  }
                  self.waiting = [];
                  win();
              };
          };
          setVrequest.onerror = function(e) {
              setVrequest.onsuccess = setVrequest.onerror = null;
              console.error("Failed to create objectstore " + e);
              fail(e);
          };
        } else {
            self.store = true;
            for (var i = 0; i < self.waiting.length; i++) {
                  self.waiting[i].call(self);
            }
            self.waiting = [];
            win();
        }
    }
    request.onerror = function(ev) {
        if (request.errorCode === getIDBDatabaseException().VERSION_ERR) {
            // xxx blow it away
            self.idb.deleteDatabase(self.name);
            // try it again.
            return self.init(options, callback);
        }
        console.error('Failed to open database');
    };
},
4

1 回答 1

1

我认为您继续添加数据而不是更新当前数据。

您能否提供有关商店配置的更多信息。您使用的是内联密钥还是外部密钥?如果它是内部的,那么密钥路径是什么。

于 2013-10-21T14:07:38.400 回答