2012-05-06 5 views
15

Ich möchte ungefähr 35000 Objekte im Objektspeicher meiner IndexedDB speichern. Ich verwende den folgenden Code zum Einfügen.Einfügen großer Mengen in die Objectstore-Blöcke von IndexedDB UI

AddListings = function (x2j_list_new, callback) { 
    var transaction = db.transaction(["listings"], IDBTransaction.READ_WRITE); 
    var count = 0; 
    transaction.oncomplete = function (event) { 
     if (callback) { 
      console.log('x2jShowListing Added ' + count + '/' + x2j_list_new.length); 
       callback([count, x2j_list_new.length]); 
      } 
    }; 
    transaction.onerror = function (e) { 
     console.log("myError: ", e); 
     if (callback) { 
      callback(false); 
     } 
    }; 
    var store = transaction.objectStore("listings"); 

    $.each(x2j_list_new, function (index0, item0) { 
     var request = store.put(item0); 
     request.onsuccess = function (event) { 
      count++; 
      // event.target.result 
      }; 
     }); 
    });   
}; 

Der obige Code funktioniert gut, aber Looping und ~ 35000 Einfügen von Objekten über macht die Benutzeroberfläche nicht mehr reagiert für ~ 200 Sekunden. Ich dachte, ich könnte vielleicht WebWorker benutzen, aber IndexedDB ist in WebWorker nicht verfügbar. Ich habe versucht, einen Weg zu finden, Massen einzufügen, konnte keinen finden. Haben Sie Ideen, wie Sie große Mengen von Objekten einfügen können, ohne die Benutzeroberfläche zu blockieren?

+1

Vorerst ich das Array bin Aufspaltung in [chunks] (http://stackoverflow.com/questions/ 8495687/split-array-in-chunks) von 500 und mit [setInterval] (http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript- Schleifen) anstelle von for loop. Jetzt reagiert die Benutzeroberfläche etwas besser als zuvor. – surya

Antwort

28

Sie sind auf dem richtigen Weg, aber Sie bitten den Browser, 35.000 Objekte zu speichern, bevor es die Möglichkeit hatte, eine zu speichern. Hier ist Code, der asynchron wartet auf eine Anfrage vor dem Start des nächsten zu beenden (aber mit der gleichen Transaktion):

openRequest = window.indexedDB.open("MyDatabase", 1); 
    openRequest.onerror = function(event) { 
     console.error(event); 
    }; 
    openRequest.onsuccess = function (event) { 
     var db = openRequest.result; 
     db.onerror = function(event) { 
      // Generic error handler for all errors targeted at this database's requests 
      console.error(event.target); 
      window.alert("Database error: " + event.target.wePutrrorMessage || event.target.error.name || event.target.error || event.target.errorCode); 
     }; 
     var transaction = db.transaction('item', "readwrite"); 
     var itemStore = transaction.objectStore("item"); 
     putNext(); 

     function putNext() { 
      if (i<items.length) { 
       itemStore.put(items[i]).onsuccess = putNext; 
       ++i; 
      } else { // complete 
       console.log('populate complete'); 
       callback(); 
      } 
     }   
    };  
+0

Interessanter Vorschlag. Neugierig - Wer irgendwelche Benchmarks auf Performance-Gewinne, die dies erreicht? –

+0

Um sicher zu sein, dass alle Elemente ** wirklich ** im Geschäft sind - abonnieren Sie das 'transaction.oncomplete' Ereignis, smt wie:' transaction.oncomplete = callback' – Kiril

+0

Ich kann nicht sehen, wie man das Ende einer Transaktion bestimmt Man bekommt ein Geschäft von der Transaktion und fügt dann einen oder mehrere Datensätze hinzu ... Wie mache ich die Transaktion zu Ende, nachdem ich alles hinzugefügt habe? Wird die Transaktion beendet, nachdem der Rückruf von onsuccess zurückgegeben wurde? Nach alle Einträge sind in diesem rekursiven Aufruf hinzugefügt? Ich gehe davon aus – lisak

0

Sie tun alles, was Sie richtig machen, indem Sie Rückrufe verwenden.

Die Webworker-API wurde noch nicht von einem größeren Browser implementiert. Interessanterweise wird erwartet, dass es synchron ist. Die reguläre API ist asynchron, genau aus dem Grund, den Sie beschreiben - sie soll den UI-Thread nicht blockieren.

Die Verwendung von Rückrufen ist der Weg, um Blockierungen zu vermeiden, aber bei 35.000 Objekten sieht man deutlich, dass dieses Paradigma zusammenbricht. Leider ist die IDB-Leistung von den Benchmarks, die ich gesehen habe, noch nicht mit WebSQL vergleichbar.

Mit Chrome's LevelDB gab es einige neue experimentelle Backends (FF ist SQLite), aber ich denke, Ihre Erfahrung zeigt, dass es noch Raum für Verbesserungen gibt.

0

Wilde Vermutung von meiner Seite, aber wenn WebSQL von so genannten "Hintergrundseite" verfügbar ist, und unter der Annahme, dass die Bandbreite der Nachrichtenübermittlung zwischen der Front- und Backpage die Benutzeroberfläche auf die gleiche Weise nicht blockiert, vielleicht könnte eine Hintergrundseite mit Intra-Page-Nachricht verwendet werden?

+0

Ich habe das Gefühl, dass es die for-Schleife ist, die Block UI verursacht. Ich wünschte, es gäbe eine Möglichkeit, den Browser in regelmäßigen Abständen zu pingen, so dass er nicht festhängt. – surya

+0

In der herkömmlichen GUI-Programmierung konnten Sie erkennen, wenn der Browser "inaktiv" ist und einen weiteren Schritt in Ihrer großen Fußschleife ausführen. Leider ist die Erkennung des Leerlaufzustands in JavaScript nicht einfach, aber es gibt Hacks, um es zu simulieren. Zum Beispiel http://stackoverflow.com/questions/667555/detecting-idle-time-in-javascript-elegantly. –

0

Ich spalte das Array in Stücke von 500 und mit setTimeout anstelle von For-Schleife. Jetzt reagiert die Benutzeroberfläche etwas besser als zuvor

+0

Ich empfehle nicht auf IndexedDB von mehreren Ereignis-Schleife Aufgaben zugreifen. Es verhält sich so komisch – lisak