You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IndexedDB初始化延迟致db未定义,事务创建失败求解决方案

解决IndexedDB初始化异步导致的db未定义问题

你碰到的问题本质是IndexedDB的数据库连接是异步建立的——indexedDB.open()不会立刻返回可用的数据库实例,而是要等到onsuccess或onupgradeneeded回调触发后,db变量才会被赋值。但你的代码在初始化完成前就直接调用了Dairy.add()和Dairy.all(),这时候db还是undefined,自然会抛出Cannot read property 'transaction' of undefined的错误。

修复方案:用Promise封装数据库初始化

我们可以把数据库的初始化过程包装成一个Promise,让所有数据库操作都等待这个Promise完成后再执行,确保db已经就绪。以下是修改后的完整代码:

// DATABASE FOR THE DIARY
const Dairy = (() => {
  if (window.indexedDB) {
    let db;
    const DB_NAME = 'Dairy';
    const DB_VERSION = 1;
    const DB_STORE_NAME = 'diaries';
    // 新增:创建一个初始化Promise,等待数据库连接完成
    const dbInitPromise = new Promise((resolve, reject) => {
      const request = window.indexedDB.open(DB_NAME, DB_VERSION);
      request.onerror = (event) => {
        console.log('Error requesting to open database permission denied.');
        reject(event.target.error);
      };
      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}`);
        };
        resolve(db); // 初始化完成,resolve Promise
      };
      request.onupgradeneeded = (event) => {
        db = event.target.result;
        const store = db.createObjectStore(DB_STORE_NAME, { keyPath: 'date' });
        store.createIndex('subject', 'subject', { unique: false });
        store.createIndex('date', 'date', { unique: true });
        store.createIndex('description', 'description', { unique: false });
        // 升级完成后,db已经可用,resolve Promise
        resolve(db);
      };
    });

    const getObjectStore = async (storeName, mode) => {
      // 等待数据库初始化完成
      await dbInitPromise;
      console.log('db from getObjectStore: ', db);
      const tx = db.transaction(storeName, mode);
      return tx.objectStore(storeName);
    };

    const getAllEntries = async () => {
      const store = await getObjectStore(DB_STORE_NAME, 'readonly');
      return new Promise((resolve) => {
        const result = [];
        const req = store.openCursor();
        req.onsuccess = (evt) => {
          const cursor = evt.target.result;
          if (cursor) {
            // 注意:数组用push而不是append
            result.push(cursor.value);
            cursor.continue();
          } else {
            console.log('No more entries');
            resolve(result);
          }
        };
      });
    };

    const setAnEntry = async (value) => {
      const store = await getObjectStore(DB_STORE_NAME, 'readwrite');
      // 用Promise包装put操作,方便调用者处理结果
      return new Promise((resolve, reject) => {
        const request = store.put(value);
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
      });
    };

    const removeAnEntry = async (value) => {
      const store = await getObjectStore(DB_STORE_NAME, 'readwrite');
      return new Promise((resolve, reject) => {
        const request = store.remove(value);
        request.onsuccess = () => resolve();
        request.onerror = () => reject(request.error);
      });
    };

    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 {};
})();

// 注意:现在所有方法都是异步的,需要用async/await处理
(async () => {
  console.log('adding something in the diary');
  try {
    await Dairy.add({ subject: 'hello', description: 'bluh bluh', date: new Date().toISOString() });
    console.log('Entry added successfully');
    const allEntries = await Dairy.all();
    console.log('show all: ', allEntries);
  } catch (err) {
    console.error('Operation failed: ', err);
  }
})();

关键修改点说明

  1. 数据库初始化Promise:用dbInitPromise封装indexedDB.open()的异步过程,在onsuccess和onupgradeneeded回调中resolve这个Promise,确保后续操作能等待db就绪。
  2. 异步化所有操作:将getObjectStore、getAllEntries、setAnEntry、removeAnEntry都改成异步函数(用async/await),确保每次操作前都等待数据库初始化完成。
  3. 修复数组操作错误:原来的result.append(value)改为result.push(value),因为JavaScript数组没有append方法。
  4. 用Promise包装数据库操作:给put和remove操作添加Promise封装,让调用者可以方便地处理成功/失败的情况。
  5. 异步调用Dairy方法:因为现在所有方法都是异步的,所以需要用async/await或者.then()来调用,避免直接同步调用导致的问题。

这样修改后,就能保证所有数据库操作都在db初始化完成后执行,不会再出现db未定义的错误了。

内容的提问来源于stack exchange,提问作者ASB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:05:09