为什么在连接到indexedDB之前有时会在onupgradeneeded之前调用onsuccess?

时间:2021-05-05 22:50:53

I am having trouble with IndexedDB. On Firefox 18, when I create a new database, the onsuccess method is called at the same time has onupgradeneeded. On Chrome 24 (this is the behavior I'd like to get), the onsuccess method is only called after the onupgradeneeded method has completed.

我在使用IndexedDB时遇到了问题。在Firefox 18上,当我创建一个新数据库时,onupccess方法在onupgradeneeded的同时被调用。在Chrome 24上(这是我想要的行为),onsuccess方法仅在onupgradeneeded方法完成后调用。

According to the MDN information on IndexedDB, I was under the impression that when the onsuccess method was called, it was safe to work with the database but this make it seems like it is not in Firefox.

根据有关IndexedDB的MDN信息,我的印象是,当调用onsuccess方法时,使用数据库是安全的,但这似乎不适用于Firefox。

(function(){
  app = {};

  // These will hold the data for each store.
  app.objectstores = [
    { name: 'UNIVERSITIES',
      keyPath: 'UID',
      autoIncrement: false,
      data_source: 'http://mysites.dev/nddery.ca_www/larelance/data/universite.json' },
  ];

  // Some information pertaining to the DB.
  app.indexedDB    = {};
  app.indexedDB.db = null
  app.DB_NAME      = 'testdb';
  app.DB_VERSION   = 1;

  /**
   * Attempt to open the database.
   * If the version has changed, deleted known object stores and re-create them.
   * We'll add the data later.
   *
   */
  app.indexedDB.open = function() {
    // Everything is done through requests and transactions.
    var request = window.indexedDB.open( app.DB_NAME, app.DB_VERSION );

    // We can only create Object stores in a onupgradeneeded transaction.
    request.onupgradeneeded = function( e ) {
      app.indexedDB.db = e.target.result;
      var db = app.indexedDB.db;

      // Delete all object stores not to create confusion and re-create them.
      app.objectstores.forEach( function( o ) {
        if ( db.objectStoreNames.contains( o.name ) )
          db.deleteObjectStore( o.name );

        var store = db.createObjectStore(
          o.name,
          { keyPath: o.keyPath, autoIncrement: o.autoIncrement }
        );

        app.indexedDB.addDataFromUrl( o.name, o.data_source );
      });
    }; // end request.onupgradeneeded()

    // This method is called before the "onupgradeneeded" has finished..??
    request.onsuccess = function( e ) {
      app.indexedDB.db = e.target.result;
      app.ui.updateStatusBar( 'Database initialized...' );

      // ***
      // Would like to query the database here but in Firefox the data has not
      // always been added at this point... Works in Chrome.
      //
    }; // end request.onsuccess()

    request.onerror = app.indexedDB.onerror;
  }; // end app.indexedDB.open()


  app.indexedDB.addDataFromUrl = function( store, url ) {
    var xhr = new XMLHttpRequest();
    xhr.open( 'GET', url, true );
    xhr.onload = function( event ) {
      if( xhr.status == 200 ) {
        console.log('*** XHR successful');
        // I would be adding the JSON data to the database object stores here.
      }
      else{
        console.error("addDataFromUrl error:", xhr.responseText, xhr.status);
      }
    };
    xhr.send();
  }; // end app.indexedDB.addDataFromUrl()
})();

Thanks!

谢谢!

2 个解决方案

#1


4  

One of the things you are probably suffering with is the auto-commit functionality in the indexeddb. If an transaction becomes inactive for a short timespan, it will commit the transaction and close it.

您可能遇到的一件事是indexeddb中的自动提交功能。如果事务在短时间内变为非活动状态,它将提交事务并将其关闭。

In your case you are calling an async method to fill up the data, and that is why the transaction probably becomes inactive. if you add a console.write after app.indexedDB.addDataFromUrl( o.name, o.data_source ); you will see it will get called before your data is retrieved, causing the commit of the transaction. That is why the data isn't present when the success callback is called. It is possible that the timeout for transactions is higher in chrome than in Firefox. It isn't described in the spec so it can vary by vendor.

在您的情况下,您正在调用异步方法来填充数据,这就是事务可能变为非活动状态的原因。如果你在app.indexedDB.addDataFromUrl(o.name,o.data_source)之后添加一个console.write;您将看到在检索数据之前它将被调用,从而导致事务的提交。这就是调用成功回调时数据不存在的原因。事务的超时可能在Chrome中比在Firefox中更高。它没有在规范中描述,因此它可能因供应商而异。

btw, if you want to add data in your ajax call, you will have to pass the object store as a parameter as well.

顺便说一句,如果你想在你的ajax调用中添加数据,你也必须将对象存储作为参数传递。

#2


0  

do what you have to do inside if( xhr.status == 200 ) {} call a transaction from there, put the data to the objectStore and what more you need

如果(xhr.status == 200){}从那里调用一个事务,将数据放到objectStore以及你需要什么,你可以做你必须做的事情

edit:

编辑:

I do it like this, works for me, the oncomplete function only gets called once all the data is inserted and the objectStore is ready for use:

我这样做,对我有用,只有在插入所有数据并且objectStore可以使用后才会调用oncomplete函数:

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://...", true);
xhr.addEventListener("load", function(){
    if(xhr.status === 200){
        console.info("Data received with success");
        var data = JSON.parse(xhr.responseText);
        var transaction = db.transaction([STORe],'readwrite');
        var objstore = transaction.objectStore(STORE);
        for(i = 0; i < data.length; i++){
            objstore.put(data[i]);
        };
        transaction.oncomplete = function(event){
            //do what you need here
            console.info("Inserted data: " + data.length);
        };
        transaction.onerror = function(event){              
        };
        transaction.onabort = function(event){
        };
        transaction.ontimeout = function(event){
        };
        transaction.onblocked = function(event){
        };                      
    };
}, false);
xhr.send();

#1


4  

One of the things you are probably suffering with is the auto-commit functionality in the indexeddb. If an transaction becomes inactive for a short timespan, it will commit the transaction and close it.

您可能遇到的一件事是indexeddb中的自动提交功能。如果事务在短时间内变为非活动状态,它将提交事务并将其关闭。

In your case you are calling an async method to fill up the data, and that is why the transaction probably becomes inactive. if you add a console.write after app.indexedDB.addDataFromUrl( o.name, o.data_source ); you will see it will get called before your data is retrieved, causing the commit of the transaction. That is why the data isn't present when the success callback is called. It is possible that the timeout for transactions is higher in chrome than in Firefox. It isn't described in the spec so it can vary by vendor.

在您的情况下,您正在调用异步方法来填充数据,这就是事务可能变为非活动状态的原因。如果你在app.indexedDB.addDataFromUrl(o.name,o.data_source)之后添加一个console.write;您将看到在检索数据之前它将被调用,从而导致事务的提交。这就是调用成功回调时数据不存在的原因。事务的超时可能在Chrome中比在Firefox中更高。它没有在规范中描述,因此它可能因供应商而异。

btw, if you want to add data in your ajax call, you will have to pass the object store as a parameter as well.

顺便说一句,如果你想在你的ajax调用中添加数据,你也必须将对象存储作为参数传递。

#2


0  

do what you have to do inside if( xhr.status == 200 ) {} call a transaction from there, put the data to the objectStore and what more you need

如果(xhr.status == 200){}从那里调用一个事务,将数据放到objectStore以及你需要什么,你可以做你必须做的事情

edit:

编辑:

I do it like this, works for me, the oncomplete function only gets called once all the data is inserted and the objectStore is ready for use:

我这样做,对我有用,只有在插入所有数据并且objectStore可以使用后才会调用oncomplete函数:

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://...", true);
xhr.addEventListener("load", function(){
    if(xhr.status === 200){
        console.info("Data received with success");
        var data = JSON.parse(xhr.responseText);
        var transaction = db.transaction([STORe],'readwrite');
        var objstore = transaction.objectStore(STORE);
        for(i = 0; i < data.length; i++){
            objstore.put(data[i]);
        };
        transaction.oncomplete = function(event){
            //do what you need here
            console.info("Inserted data: " + data.length);
        };
        transaction.onerror = function(event){              
        };
        transaction.onabort = function(event){
        };
        transaction.ontimeout = function(event){
        };
        transaction.onblocked = function(event){
        };                      
    };
}, false);
xhr.send();