简体   繁体   English

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

[英]Global variable only accessible to first function?

I have an OK understanding of JS but am ultimately still learning.我对 JS 有很好的理解,但最终仍在学习。 I'm trying to recreate a PHP/mySQL project over to IndexedDB and can't work out why I'm seeing an error here.我正在尝试将 PHP/mySQL 项目重新创建到 IndexedDB,但无法弄清楚为什么我在这里看到错误。

The IndexedDB connection works as expected. IndexedDB 连接按预期工作。 The first function (createItem) functions fine, however the second function (getItems) is returning an error claiming that the "db" variable is undefined.第一个函数 (createItem) 运行正常,但是第二个函数 (getItems) 返回一个错误,声称“db”变量未定义。 It's a global variable so should be accessible by the function's scope, and the createItem function has no problem using it.它是一个全局变量,因此应该可以通过函数的作用域访问,并且 createItem 函数使用它没有问题。 Can anyone help me see what I've missed here.谁能帮我看看我在这里错过了什么。

// 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);
        }
    }
};

As you've figured out in comments, you do have to stick the db-dependent actions inside a function called from a success handler.正如您在评论中发现的那样,您必须将依赖于 db 的操作放入从success处理程序调用的函数中。

This callback-based programming quickly becomes a pain, and a common solution for that is to use promises .这种基于回调的编程很快就变得很痛苦,一个常见的解决方案是使用promises

However, making IndexedDB work with promises is still work-in-progress (see https://github.com/inexorabletash/indexeddb-promises if you're interested).但是,使 IndexedDB 与 promise 一起工作仍在进行中(如果您有兴趣,请参阅https://github.com/inexorabletash/indexeddb-promises )。

If your goal is to get something done (and not to learn the bare IndexedDB APIs), perhaps you'd be better off finding a wrapper library for IndexedDB (can't recommend one though, since I've not tried working seriously with IDB yet).如果您的目标是完成某事(而不是学习裸的 IndexedDB API),也许您最好为 IndexedDB找到一个包装库(虽然不能推荐一个,因为我还没有尝试过认真地使用 IDB然而)。

I would not recommend using a variable like 'db' as you have in your example.我不建议像您在示例中那样使用像 'db' 这样的变量。 If you are new to reading and writing asynchronous Javascript, you are just going to cause yourself a lot of pain.如果您刚开始阅读和编写异步 Javascript,那么您只会给自己带来很多痛苦。 There are better ways to do it.有更好的方法来做到这一点。 It takes several pages to explain and is explained in many other questions on StackOverflow, so instead, very briefly, consider rewriting your code to do something like the following:这需要几页来解释,并且在 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, ...);
  };
}

Also, you don't need to wait for DOMContentLoaded to start using indexedDB.此外,您无需等待 DOMContentLoaded 开始使用 indexedDB。 It is immediately available.它是立即可用的。

If you get the above code, then you can consider a further improvement of adding a simple helper function:如果你得到了上面的代码,那么你可以考虑进一步改进,添加一个简单的辅助函数:

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

And then rewrite the examples like this:然后像这样重写示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM