首页 > 解决方案 > IndexedDB 需要时间来初始化另一个函数所需的外部范围变量 db

问题描述

我正在使用 indexedDB 打开一个数据库,使用 javascript 来保存日记条目。我正在对数据库做三件事:显示所有条目、添加条目和删除条目。

它在尝试创建事务时失败,因为“db”是“未定义的”。我期望 db 在代码尝试创建事务时定义。

错误是在代码行引起的:

      const getObjectStore = (storeName, mode) => {
        console.log('db: ', db);
        const tx = db.transaction(storeName, mode); // error is thrown because db is undefined
        return tx.objectStore(storeName);
      };

我试图将 console.log 放在不同的地方,看看有什么问题。我发现 db 在被 onsuccess 响应或 onupgradeneeded 响应定义之前需要一些时间。在使用之前,我看不到任何其他定义 db 的方法。你能告诉我如何在使用 db 之前保证自己的分配吗?

输出:

> adding something in the diary
> db from getObjectStore:  undefined
> Uncaught TypeError: Cannot read property 'transaction' of undefined
    at getObjectStore (script.js:35)
    at Object.setAnEntry [as add] (script.js:62)
    at script.js:81
    at script.js:215
getObjectStore @ script.js:35
setAnEntry @ script.js:62
(anonymous) @ script.js:81
(anonymous) @ script.js:215
> there is indexeddb!
> db:  IDBDatabase {name: "medDiary", version: 1, objectStoreNames: DOMStringList, onabort: null, onclose: null, …}

我正在使用的所有代码:

  // DATABASE FOR THE DIARY

  const Dairy = (() => {
    if (window.indexedDB) {
      let db;
      const DB_NAME = 'Dairy';
      const DB_VERSION = 1;
      const DB_STORE_NAME = 'diaries';
      const request = window.indexedDB.open(DB_NAME, DB_VERSION);

      request.onerror = () => {
        console.log('Error requesting to open database permission denied.');
      };
      request.onsuccess = (event) => {
        console.log('there is indexeddb!');
        db = event.target.result;
        console.log('db: ', db);
        db.onerror = (evt) => {
          console.error(`Database error: ${evt.target.errorCode}`);
        };
      };

      request.onupgradeneeded = (event) => {
        db = request.result;
        const store = event.currentTarget.result.createObjectStore(DB_STORE_NAME, { keyPath: 'date' });
        store.createIndex('subject', 'subject', { unique: false });
        store.createIndex('date', 'date', { unique: true });
        store.createIndex('description', 'description', { unique: false });
      };

      const getObjectStore = (storeName, mode) => {
        console.log('db from getObjectStore: ', db);
        const tx = db.transaction(storeName, mode);
        return tx.objectStore(storeName);
      };

      const getAllEntries = () => new Promise((resolve) => {
        const result = [];
        const store = getObjectStore(DB_STORE_NAME, 'readonly');
        const req = store.openCursor();

        req.onsuccess = (evt) => {
          const cursor = evt.target.result;

          if (cursor) {
            const retrive = store.get(cursor.key);
            retrive.onsuccess = function (evt) {
              const value = evt.target.result;
              result.append(value);
            };
            cursor.continue();
          } else {
            console.log('No more entries');
            resolve(result);
          }
        };
      });

      const setAnEntry = (value) => {
        const store = getObjectStore(DB_STORE_NAME, 'readwrite');
        store.put(value);
      };
      const removeAnEntry = (value) => {
        const store = getObjectStore(DB_STORE_NAME, 'readwrite');
        store.remove(value);
      };

      return {
        all: getAllEntries,
        add: setAnEntry,
        remove: removeAnEntry,
      };
    }
    alert("Your browser doesn't support a stable version of IndexedDB. Dairy related features will not be available.");
    return {};
  })();

  console.log('adding something in the diary');
  console.log('... ', Dairy.add({ subject: 'hello', description: 'bluh bluh', date: Date() }));
  console.log('show all: ', Dairy.all());

标签: javascriptindexeddb

解决方案


您可以使用承诺打开数据库:

let promise = new Promise(function(resolve, reject)
        {
            //check for support
            if (!('indexedDB' in window)) {
                //console.log('This browser doesn\'t support IndexedDB');
                reject("indexedDB not supported");
            }

            var request = indexedDB.open(dbName, dbVersion);
            request.onerror = function (event) {
                reject("Error opening DB");
            };
            request.onsuccess = function (event) {
                console.log("opened!");
                db = request.result;
                resolve(true);
            };
        });

然后你可以使用:

promise
    .then(
        result => {
            your stuff here sine the DB is now open!!
        },
        error => console.log(error)
    )

传递给解析的参数将作为“结果”提供。

要在您的模块格式中使用:添加 init 函数:

async function init()
{
    let promise = new Promise(function(resolve, reject)
        {
            //check for support
            if (!('indexedDB' in window)) {
                //console.log('This browser doesn\'t support IndexedDB');
                reject("indexedDB not supported");
            }

            var request = indexedDB.open(dbName, dbVersion);
            request.onerror = function (event) {
                reject("Error opening DB");
            };
            request.onsuccess = function (event) {
                console.log("opened!");
                db = request.result;
                resolve(true);
            };
        });
    let result = await promise;
}

您的模块重写:

const Dairy = (() => {
    if (window.indexedDB)
    {
        let db;
        const DB_NAME = 'Dairy';
        const DB_VERSION = 1;
        const DB_STORE_NAME = 'diaries';
        async function init()
        {
            let promise = new Promise(function(resolve, reject)
            {
                const request = window.indexedDB.open(DB_NAME, DB_VERSION);

                request.onerror = () => {
                    reject('Error requesting to open database permission denied.');
                };
                request.onsuccess = (event) => {
                    console.log('there is indexeddb!');
                    db = event.target.result;
                    console.log('db: ', db);
                    db.onerror = (evt) => {
                        reject("Database error: ${evt.target.errorCode}");
                    };
                    resolve(true);
                };

                request.onupgradeneeded = (event) => {
                    db = request.result;
                    const store = event.currentTarget.result.createObjectStore(DB_STORE_NAME, { keyPath: 'date' });
                    store.createIndex('subject', 'subject', { unique: false });
                    store.createIndex('date', 'date', { unique: true });
                    store.createIndex('description', 'description', { unique: false });
                };
            });
            return promise;
        }

      const getObjectStore = (storeName, mode) => {
        console.log('db from getObjectStore: ', db);
        const tx = db.transaction(storeName, mode);
        return tx.objectStore(storeName);
      };

      const getAllEntries = () => new Promise((resolve) => {
        const result = [];
        const store = getObjectStore(DB_STORE_NAME, 'readonly');
        const req = store.openCursor();

        req.onsuccess = (evt) => {
          const cursor = evt.target.result;

          if (cursor) {
            const retrive = store.get(cursor.key);
            retrive.onsuccess = function (evt) {
              const value = evt.target.result;
              result.append(value);
            };
            cursor.continue();
          } else {
            console.log('No more entries');
            resolve(result);
          }
        };
      });

      const setAnEntry = (value) => {
        const store = getObjectStore(DB_STORE_NAME, 'readwrite');
        store.put(value);
      };
      const removeAnEntry = (value) => {
        const store = getObjectStore(DB_STORE_NAME, 'readwrite');
        store.remove(value);
      };

      return {
        all: getAllEntries,
        add: setAnEntry,
        remove: removeAnEntry,
        init: init
      };
    }
    alert("Your browser doesn't support a stable version of IndexedDB. Dairy related features will not be available.");
    return {};
  })();
  Dairy.init()
    .then(
        result => {
            console.log('adding something in the diary');
            console.log('... ', Dairy.add({ subject: 'hello', description: 'bluh bluh', date: Date() }));
            console.log('show all: ', Dairy.all());
        },
        error => console.log(error)
    );

推荐阅读