2016-06-04 5 views
0

Also, für mein Wochenende Projekt wählte ich IndexedDB lernen. Ich versuche etwas wie ein DAO zu erstellen (Entschuldigung, es ist der Java-Entwickler in mir). Hier ist, was ich habe:Indizierte Datenbank: Datenbank nicht initialisiert

function ReceiptDB() { 

    this.db = null; 
    this.dbname = "Receipts"; 
    this.dbver = 2; 

    this.getDB = function() { 
     return db; 
    }; 

    this.setDB = function(dbresult) { 
     db = dbresult; 
    }; 


    var topThis = this; 
    this.initialize = function() { 

     alert("Running init"); 

     var promise = $.Deferred(); 

     var request = indexedDB.open(this.dbname, this.dbver); 

     request.onsuccess = function(e) { 
      topThis.db = e.target.result; 
      topThis.setDB(e.target.result); 
      promise.resolve(); 
     }; 

     request.onupgradeneeded = function(e) { 
      console.log("Upgrading database"); 
      var db = event.target.result; 
      if (!db.objectStoreNames.contains("GroupIDs")) { 
       var groupIdObjectStore = db.createObjectStore("GroupIDs"); 
      } 

      if (!db.objectStoreNames.contains("Locations")) { 
       var storesObjectStore = db.createObjectStore("Locations"); 
      } 

     }; 

     request.onfailure = function(e) { 
      alert("failed to open db"); 

      //topThis.initPromise.reject(); 
      promise.reject(); 
     }; 

     request.onerror = function(e) { 
      alert("init error: " + e.target.errorCode); 
      promise.reject(); 
     }; 

     return promise; 
    }; 

    this.getAllGroupIds = function() { 

     var promise = $.Deferred(); 

     var results = []; 

     var db = topThis.db; 
     if (!db) { 
      alert("DB not initialized!"); 
     } 

     var tx = topThis.db.transaction("GroupIDs", "readonly"); 
     var store = tx.objectStore("GroupIDs"); 

     store.openCursor().onsuccess = function(e) { 
      var cursor = event.target.result; 
      if (cursor) { 
       results.push(cursor.value); 
       cursor.continue(); 
      } 

      promise.resolve(results); 
     }; 

     return promise; 
    }; 

    this.init(); 


}; 

I auslösen dies mit einer HTML-Taste:

$(document).ready(function() { 

    $("#btn1").click(function(e) { 

     var receiptdb = new ReceiptDB(); 
     var initPromise = receiptdb.initialize(); 

     $.when(initPromise).done(function() { 
      console.log("receiptdb promise done"); 
      var getAllPromise = receiptdb.getAllGroupIds(); 
     }); 

    }); 
} 

Ich bin mit dem Versprechen, um sicherzustellen, dass das Objekt der Datenbank initialisiert, bevor ich versuche, eine Abfrage, um sie auszuführen . Leider funktioniert es nicht: Wenn ich die Methode getAllGroupIds() aufruft, ist die Datenbank leer. Für mich hätte das mit der init Methode erledigt werden sollen.

Kann mir jemand sagen, wo ich falsch gelaufen bin?

Bearbeiten: Ich habe die Initialisierungsfunktion in initialize() umbenannt und rufe sie manuell auf, weil es für einen Konstruktor wenig Sinn macht, einen Wert aufzurufen. Jason

Bearbeiten 2: Bevor ich Josh Antwort sah, wechselte ich die Gänge. Ich benutze immer noch Versprechungen.

function openDatabase(DBNAME, DBVER) { 

var promise = $.Deferred(); 

var request = window.indexedDB.open(DBNAME, DBVER); 

request.onsuccess = function(e) { 
    console.log("Successfully opened DB"); 
    promise.resolve(e.target.result); 
}; 

request.onupgradeneeded = function(e) { 
    console.log("configuring database"); 
    // create datastores and indexes 
}; 

request.onfailure = function(e) { 
    promise.reject(); 
}; 

request.onerror = function(e) { 
    console.log("Error opening database: " + e.target.errorCode); 
    promise.reject(); 
}; 

} 

An diesem Punkt könnte ich ein Repository erstellen, solange das Versprechen gelöst:

function Repository(database) { 
    this.db = database; 

    this.get = function(id) { 
     // get an item by id, return a promise (again) since the 
     // result is inside another onsuccess callback 
    } 

    // rest of crud functions 
} 
var dbPromise = openDatabase("mydb", 1); 
$.when(dbPromise).done(function(db) { 
    var repo = new Repository(db); 

    var resultPromise = repo.get(id); 
    $.when(resultPromise).done(function(result)) { 
     // do something with the result 
    }; 
}); 

Ich mag nicht den verschachtelten .when $ viel, aber es scheint zu funktionieren Ich

+1

Nested Versprechen in der Regel mit Versprechen Ketten ersetzt werden kann. z.B. (unter der Annahme, dass JS tablesnable ist): f(). then (Funktion (a) {a.foo(); ... return b;}). then (Funktion (b) {b.bar(); ...}); –

Antwort

1

Erste Rate, es ist, wenn Sie e.target.result zu topThis.db zuweisen. Sie ordnen einem unabhängigen äußeren Bereich einen Wert zu, der nur innerhalb seines Bereichs oder abhängigen Bereichen gültig ist.

Ich würde vorschlagen, etwas Zeit damit zu verbringen, async js zu schreiben, bevor Sie fortfahren. Außerdem würde ich Ihnen persönlich empfehlen, Versprechungen zu vermeiden, denn angesichts der Art des Problems, das Sie gerade erleben, verschärfen Sie nur die Komplexität des Problems und verdunkeln es sogar.

Kurz, anstatt die globale db-Variable als Reaktion auf den onclick zu referenzieren, öffnen Sie eine neue Verbindung. Als nächstes übergeben Sie das als ersten Parameter an Ihre anderen Funktionen. In Bezug auf das Schreiben von Async-Code schreiben Sie stattdessen Funktionen, die Ergebnisse an Callback-Funktionen übergeben, anstatt zu versuchen, Funktionen zu schreiben, die Werte zurückgeben.

Um Ihnen den Einstieg, sicherzustellen, dass Sie das folgende verstehen:

var x; 
function setOuterX() { 
    x = 'Hello World'; 
} 
setTimeout(setOuterX, 0); 
console.log(x);