2016-05-10 4 views
2

Ich habe ein OK-Verständnis von JS, aber lerne letztlich immer noch. Ich versuche, ein PHP/mySQL-Projekt auf IndexedDB neu zu erstellen und kann nicht herausfinden, warum hier ein Fehler angezeigt wird.Globale Variable nur für die erste Funktion zugänglich?

Die IndexedDB-Verbindung funktioniert wie erwartet. Die erste Funktion (createItem) funktioniert gut, die zweite Funktion (getItems) gibt jedoch einen Fehler zurück, der behauptet, dass die Variable "db" nicht definiert ist. Es ist eine globale Variable, daher sollte der Bereich der Funktion darauf zugreifen können, und die Funktion createItem hat kein Problem damit. Kann mir jemand helfen zu sehen, was ich hier verpasst habe?

// GLOBAL DB VAR 
var db; 
// WAIT FOR DOM 
document.addEventListener("DOMContentLoaded", function(){ 
    // IF INDEXED DB CAPABLE 
    if("indexedDB" in window) { 
     // OPEN DB 
     var openRequest = indexedDB.open("newTabTest",1); 
     // CREATE NEW/UPDATE 
     openRequest.onupgradeneeded = function(e) { 
      // Notify user here: creating database (first time use) 
      var thisDB = e.target.result; 
      // Create "items" table if it doesn't already exist 
      if(!thisDB.objectStoreNames.contains("items")) { 
       var store = thisDB.createObjectStore("items", {keyPath: "id", autoIncrement: true}); 
       store.createIndex("name","name", {unique:true}); 
       store.createIndex("folder","folder", {unique:false}); 
       store.createIndex("dial","dial", {unique:false}); 
      } 
     } 
     openRequest.onsuccess = function(e) { 
      // Success- set db to target result. 
      db = e.target.result; 
     } 
     openRequest.onerror = function(e) { 
      // DB ERROR :-(
     } 
    } 
},false); 

// CREATE ITEM FUNCTION 
function createItem(n,u,f,c) { 
    var transaction = db.transaction(["items"],"readwrite"); 
    var store = transaction.objectStore("items"); 
    var item = { 
     name: n, 
     url: u, 
     folder: f, 
     colour: c, 
     dial: 0, 
     order: 100 
    } 
    var request = store.add(item); 
    request.onerror = function(e) { 
     console.log("An error occured."); 
    } 
    request.onsuccess = function(e) { 
     console.log("Successfully added.") 
    } 
}; 

// GET ITEM(S) FUNCTION 
// Specify index and key value OR omit for all 
function getItems(callback, ind, key) { 
    var transaction = db.transaction(["items"],"readonly"); 
    var store = transaction.objectStore("items"); 
    var response = []; 

    // If args are omitted - grab all items 
    if(!ind | !key) { 
     var cursor = store.openCursor(); 
     cursor.onsuccess = function(e) { 
      var res = e.target.result; 
      if(res) { 
       var r = { 
        "name": res.value['name'], 
        "url": res.value['url'], 
        "folder": res.value['folder'], 
        "colour": res.value['colour'], 
        "dial": res.value['dial'], 
        "order": res.value['order'] 
       }; 
       response.push(r); 
       res.continue(); 
      } 
     } 
     cursor.oncomplete = function() { 
      callback(response); 
     } 
    } else { 
     // If both args are specified query specified index 
     store = store.index(ind); 
     var range = IDBKeyRange.bound(key, key); 
     store.openCursor(range).onsuccess = function(e) { 
      var res = e.target.result; 
      if(res) { 
       var r = { 
        "name": res.value['name'], 
        "url": res.value['url'], 
        "folder": res.value['folder'], 
        "colour": res.value['colour'], 
        "dial": res.value['dial'], 
        "order": res.value['order'] 
       }; 
       response.push(r); 
       res.continue(); 
      } 
     } 
     cursor.oncomplete = function() { 
      callback(response); 
     } 
    } 
}; 
+4

Ich glaube, Sie‘ Ich finde die zweite Funktion * ist * Zugriff auf die Variable, aber dass sein * Wert * ist "undefiniert". Woher nennst du die Funktion? Ich stelle mir vor, dass Sie es aufrufen, bevor der asynchrone Code, der 'db = ...' setzt, ausgeführt wird. – nnnnnn

+0

Ich habe versucht, einen Aufruf von getItems unterhalb des obigen Skripts zu halten, aber selbst ohne die Funktion aufzurufen, bekomme ich einen Fehler in der Konsole, dass db in dieser Zeile nicht definiert ist. –

+0

Ahhh. Vielleicht bist du dort unterwegs! Ich muss mich wirklich in diesem asynchronen Geschäft zurechtfinden. Wie kann ich das zuverlässig machen? Vielleicht kleben meine db-abhängigen Aktionen in einer Funktion, die selbst von der indexeddb oncomplete aufgerufen wird? –

Antwort

2

Wie Sie in den Kommentaren herausgefunden haben, müssen Sie die db-abhängige Aktionen innerhalb einer Funktion von einem success Handler aufgerufen bleiben.

Diese Callback-basierte Programmierung wird schnell zu einem Schmerz, und eine gemeinsame Lösung dafür ist promises zu verwenden.

Allerdings ist die Arbeit mit IndexedDB mit Versprechungen noch in Arbeit (siehe https://github.com/inexorabletash/indexeddb-promises, wenn Sie interessiert sind).

Wenn Ihr Ziel ist, etwas zu erledigen (und nicht die nackten IndexedDB-APIs zu lernen), wäre es vielleicht besser, eine wrapper library for IndexedDB zu finden (kann ich aber nicht empfehlen, da ich nicht ernsthaft damit gearbeitet habe) IDB noch nicht).

0

Ich würde nicht empfehlen, eine Variable wie 'db' zu verwenden, wie Sie in Ihrem Beispiel haben. Wenn Sie zum Lesen und Schreiben asynchronen Javascript neu sind, werden Sie nur eine Menge Schmerzen verursachen. Es gibt bessere Möglichkeiten, es zu tun. Es dauert mehrere Seiten zu erklären, und in vielen anderen Fragen auf Stackoverflow, so stattdessen sehr kurz, betrachtet Umschreiben Code zu tun, so etwas wie die folgenden erklärt:

function createItem(db, ...) { 
    var tx = db.transaction(...); 
    // ... 
} 

function openIndexedDBThenCreateItem(...) { 
    var openRequest = indexedDB.open(...); 
    openRequest.onsuccess = function(event) { 
    var db = event.target.result; 
    createItem(db, ...); 
    }; 
} 

function getItems(db, callback, ...) { 
    var tx = db.transaction(...); 
    var items = []; 
    tx.oncomplete = function(event) { 
    callback(items); 
    }; 

    // ... 
    var request = store.openCursor(...); 
    request.onsuccess = function(event) { 
    var request = event.target; 
    var cursor = event.target.result; 
    if(cursor) { 
     var item = cursor.value; 
     items.push(item); 
     cursor.continue(); 
    } 
    }; 
} 

function openIndexedDBThenGetItems(db, callback, ...) { 
    var openRequest = indexedDB.open(...); 
    openRequest.onsuccess = function(event) { 
    var db = event.target.result; 
    getItems(db, callback, ...); 
    }; 
} 

Auch brauchen Sie nicht zu warten DOMContentLoaded, um indexedDB zu verwenden. Es ist sofort verfügbar.

Wenn Sie den obigen Code zu bekommen, dann können Sie eine weitere Verbesserung der Zugabe eines einfachen Hilfsfunktion betrachten:

function openIndexedDB(callback) { 
    var openRequest = indexedDB.open(...); 
    openRequest.onerror = callback; 
    openRequest.onsuccess = callback; 
} 

Und dann schreiben Sie die Beispiele wie folgt aus:

function openIndexedDBThenCreateItem(...) { 
    openIndexedDB(function onOpen(event) { 

    if(event.type !== 'success') { 
     console.error(event); 
    } else { 
     var db = event.target.result; 
     createItem(db, ...); 
    } 
    }); 
} 

function openIndexedDBThenGetItems(...) { 
    openIndexedDB(function onOpen(event) { 
    if(event.type !== 'success') { 
     console.error(event); 
    } else { 
     var db = event.target.result; 
     getItems(db, ...); 
    } 
    }); 
}