【javascript】indexedDB

まだ、イマイチ感がある。

注意点

1.PC上のHTMLの場合、データベースのスコープ(有効範囲)はPC単位。

つまりPC上のHTMLで共有してしまう

2.データベースをオープンしたら、必ず自分でクローズすること

クローズし忘れると、次のオープン時にロックしやすい

大抵はF5のオートコミットで済むが、ブラウザを閉じないとダメな場合もある

successイベントは1回のみなので、try catchの後のfinallyでクロースすればいい

const request = window.indexedDB.open("TestDatabase");
request.addEventListener('success', (event) => {
  const database = event.target.result;
  try {
    ・・・データ処理・・・
  } catch (ex) {
    console.log(`${ex}`);
  } finally {
    database.close();
  }
});

しかし、Promiseを使って処理の同期を取りたい場合は・・・

const promise = new Promise( (resolve, reject) => {
  const request = window.indexedDB.open("TestDatabase");
  request.addEventListener('success', (event) => {
    const database = event.target.result;
    try {
      ・・・データ処理・・・
   resolve(`xxxx(...): success`);
    } catch (ex) {
      console.log(`${ex}`);
   reject(`xxxx(...): catch(${ex})`);
    } finally {
      database.close();
    }
  });
  *** エラー処理とか ***
});
return promise;

とすると、resolveの後にfinally句のクローズ処理が通るかどうか?

あまり自信が無い。

と云うのも

function test() {
  return  true;
  alert('OK');
}

のalert(‘OK’);がいつのまにか処理されなくなってたからだ。

upgradeneeded発生時は、後にsuccessイベントが続くので、successイベントに任せればいい

errorイベントも忘れずにクローズ。

request.addEventListener('error', (event) => {
  const error = event.target.error;
  database.close();
  reject(`xxxx(...): error\n${error}`);
});

3.オブジェクトストアの生成・削除はデータベースのバージョンアップ時のみ

4.インデックスの生成・削除もデータベースのバージョンアップ時のみ

5.だが、トランザクションはデータベースのバージョンアップ時は不可

6.トランザクションも自分でcommitabortすること

commitabortを忘れるとタイムアウトするまで次の処理がロックする

const trans = database.transaction(オブジェクトストア・リスト);
try {
  const objectStore = trans.objectStore(オブジェクトストア);
  ***データ処理***
  trans.commit();
} catch (ex) {
  trans.abort();
  throw ex;
}

だからと云ってcursorのsuccessイベントは何回も降ってくることが多いので

毎回commitすると、2周目でつまずく

const trans = database.transaction(オブジェクトストア・リスト);
try {
  const objectStore = trans.objectStore(オブジェクトストア);
  const cursor objectStore.createCursor().onsuccess(event => {
    const cursor = event.target.result;
    ***データ処理***
    cursor.continue();
    trans.commit(); //毎回コミットは・・・
  });
} catch (ex) {
  trans.abort();
  throw ex;
}

7.インデックスの生成・削除できるタイミングはオブジェクトストアの生成直後だけ

const request = indeedDB.openDatabase(データベース名)
request.addEventListener(`onupgradeneed', (event) => {
  const database = event.target.result;
  const objectStore = database.createObjectStore(オブジェクトストア名);
  objectStore.createIndex(インデックス名);
  objectStore.deleteIndex(インデックス名);
});

後でインデックスを調整したい場合は、オブジェクトストアのexports機能を自作して、イジって、importsするしかない。

8.カーソルの生成はデータベースのバージョンアップ時は不可だと思う

9.カーソルのsuccessイベントはカーソルの移動回数分繰り返すので、Promise使った方が良さそう

最終のsuccessイベントは、event.target.result === undefined なので、うっかりcursor.valueすると痛い。resolveだけ処理すればいい。

const trans = database.transaction(オブジェクトストア名);
const promise = new Promise( (resolve, reject) => {
  try {
    const objectStore = trans.objectStore(オブジェクトストア名);
    const cursor = objectStore.openCursor();
    cursor.onsuccess = (event) => {
      var cursor = event.target.result;
      if (cursor) {
        console.log(`${cursor.key} is ${cursor.value}.`);
        cursor.continue();
      } else {
        console.log("end");
        resolve(true);
      }
    };
    cursor.onerror = (event) => {
      const error = event.target.error;
      reject(error);
    };
  } catch (ex) {
    reject(ex);
  }
});
return promise;

な感じだった。

データベースの構成をイジる処理をコードしてみると、

何かと面倒くさかったので、

全データベースまたはオブジェクトストア単位でのexportsimports機能を作って、

データを編集するコード(createDatabasedeleteDatabaseとか)を

使いまわしをした方が良さそう。

どうせやることは、

class IndexedDbOp {
  constractor(json) {
    this.json;
  };
  const createDatabase = (databaseName) => {
    this.json.databases[this.json.databases.length] = {'database':{
    'name': databaseName,
    'version': 1
    }}
    return this;
  }
  const deleteDatabase = (databaseName) => {
    this.json.databases = this.json.databases.filter( database => database.name !== databaseName );
    return this;
  }
  ・・・以下同文・・・
}

なのにブラウザにはindexedDBのexportsimports機能が付いていない不思議。

※上記のソースコードは雰囲気です。




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA