全局变量只能访问第一个函数?

时间:2016-05-10 01:06:10

标签: javascript indexeddb

我对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);
        }
    }
};

2 个答案:

答案 0 :(得分:2)

正如您在评论中指出的那样,您必须将依赖于数据库的操作放在从success处理程序调用的函数中。

这种基于回调的编程很快就会变得很痛苦,一个常见的解决方案就是使用promises

但是,使IndexedDB与promises一起使用仍在进行中(如果您有兴趣,请参阅https://github.com/inexorabletash/indexeddb-promises。)

如果您的目标是完成某项工作(而不是学习裸的IndexedDB API),或许您最好找一个wrapper library for IndexedDB(不能推荐一个,因为我和#39;我还没有尝试过与IDB认真合作。)

答案 1 :(得分: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, ...);
     }
  });
}