在 class 中实现异步 indexedDB 的简洁方法

Clean way to implement async indexedDB in class

我有一个 class 加载 indexedDB。在 class 中的方法可以访问它之前,我需要预先加载 indexedDB。目前我在任何其他没有初始化 this.db 的方法之前使用 init() 方法。

我正在寻找一种更简洁的方法来实现我所拥有的,这绝对不是 DRY。基本上每个方法目前都使用下面相同的代码模式实现。

问题点是:

  1. 另一个方法的要求 init() 为了正确 处理 indexedDB 的初始化。
  2. if (!this.db) { 片段稍后会自行重复。

export default class Persist {
  constructor(storage) {
    if (storage) {
      this.storage = storage;
    }
    else {
      throw new Error('A storage object must be passed to new Persist()');
    }
  }

  // needed to ensure that indexedDB is initialized before other methods can access it.
  init () {
    // initialize indexedDB:
    const DBOpenRequest = this.storage.open('db', 1);

    DBOpenRequest.onupgradeneeded = () => {
      const db = DBOpenRequest.result;
      db.createObjectStore('db', { keyPath: 'id', autoIncrement: true });
    };

    return new Promise((resolve, reject) => {
      DBOpenRequest.onerror = event => {
        reject(event);
      };

      DBOpenRequest.onsuccess = event => {
        console.log(`IndexedDB successfully opened: ${event.target.result}`);
        resolve(event.result);
        this.db = DBOpenRequest.result;
      };
    });
  }

  toStorage(session) {
    if (!this.db) {
      return this.init().then(() => {
        const db = this.db;
        const tx = db.transaction('db', 'readwrite');
        const store = tx.objectStore('db');
        const putData = store.put(session.toJS());

        return new Promise((resolve, reject) => {
          putData.onsuccess = () => {
            resolve(putData.result);
          };

          putData.onerror = () => {
            reject(putData.error);
          };
        });
      });
    }

    // basically a repeat of above
    const db = this.db;
    const tx = db.transaction('db', 'readwrite');
    const store = tx.objectStore('db');
    const putData = store.put(session.toJS());

    return new Promise((resolve, reject) => {
      putData.onsuccess = () => {
        resolve(putData.result);
      };

      putData.onerror = () => {
        reject(putData.error);
      };
    });
  }

indexedDB 提供异步功能。 indexedDB.open 是一个异步函数。看起来您正在尝试以非异步方式使用 indexedDB。不是将 IDBDatabase 变量存储为 class 实例的 属性,而是将其 return 作为解析值并在 class.[=12 外部管理它=]

function connect(name, version) {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(name, version);
    request.onupgradeneeded = myUpgradeHandlerFunction;
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
    request.onblocked = () => { console.log('blocked'); };
  });
}

function doStuffWithConn(conn, value) {
  return new Promise((resolve, reject) => {
    const tx = conn.transaction(...);
    const store = tx.objectStore(...);
    const request = store.put(value);
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
}

async function putValue(value) {
  let conn;
  try {
    conn = await connect(...);
    await doStuffWithConn(conn, value);
  } catch(exception) {
    console.error(exception);
  } finally {
    if(conn)
      conn.close();
  }
}