2016-05-10 76 views
2

我對JS有一個很好的理解,但最終還是在學習。我試圖重新創建一個PHP/mySQL項目到IndexedDB,並不能解決爲什麼我在這裏看到一個錯誤。全局變量只能通過第一個函數訪問嗎?

IndexedDB連接按預期工作。第一個函數(createItem)正常工作,但第二個函數(getItems)返回一個錯誤,聲明「db」變量未定義。它是一個全局變量,因此應該可以通過函數的作用域來訪問,而createItem函數在使用它時沒有問題。任何人都可以幫助我看看我在這裏錯過了什麼。

// 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

我想你」會發現第二個函數*是*訪問變量,但是它的*值*是「未定義的」。你從哪裏調用函數?我想你會在設置'db = ...'的異步代碼運行之前調用它。 – nnnnnn

+0

我試着在上面的腳本下面插入一個getItems的調用,但是即使沒有調用這個函數,我在控制檯中關於db在該行上未定義的錯誤也會出現。 –

+0

啊。你可能會在那裏的東西!我真的需要爲這個異步業務感到頭痛。我怎樣才能可靠地完成這項工作?也許堅持我的數據庫依賴操作內部函數本身是由indexeddb oncomplete調用? –

回答

2

正如你在評論想通了,你就必須堅持一個從success處理程序調用函數內部的DB-有關動作。

這種基於回調的編程很快就變成了一種痛苦,對此的常見解決方案是使用promises

但是,使IndexedDB與承諾一起工作仍在進行中(如果您有興趣,請參閱https://github.com/inexorabletash/indexeddb-promises)。

如果你的目標是完成一些事情(而不是學習純粹的IndexedDB API),也許你會更好找到wrapper library for IndexedDB(儘管我不曾推薦過,但因爲我沒有嘗試過認真工作IDB)。

0

我不會推薦像你的例子那樣使用像'db'這樣的變量。如果你對閱讀和編寫異步Javascript感興趣,你只會給自己造成很大的痛苦。有更好的方法來做到這一點。這需要好幾頁來解釋和StackOverflow上許多其他問題進行了說明,所以不是很簡單,考慮重寫你的代碼做一些類似如下:

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, ...); 
    }; 
} 

而且,你不需要等待DOMContentLoaded開始使用indexedDB。它立即可用。

如果得到上面的代碼,那麼你可以考慮增加一個簡單的輔助功能的進一步改善:

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

於是重寫的例子是這樣的:

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, ...); 
    } 
    }); 
}