ブラウザDBを使ってWebシステムをオフラインでも利用できるサイトにリニューアルします。
開発経緯や開発者による苦労話 | オフラインで利用できるシステムを作るための技術としてHTML5を採用しました。
ところがHTML5の仕様群はまだ完全ではなく、ブラウザのバージョンが更新されたときに動かなくなる可能性があります。特に、ブラウザにデータベースを持たせる機能は動かなくなる可能性が高く、この仕組みの実現性が危ぶまれました。
HTML5のAPIでブラウザにデータベースを作成する方法は、2013年2月時点で2通りあります。 一つがWebSQLDatabaseであり、もう一つはIndexed Databaseです。 WebSQLDatabaseは、いくつかのブラウザで最も実現が進んでいるにもかかわらず、仕様として凍結が決まってしまっています。他方でIndexed Databaseは標準となるだろうと言われていますが、まだきちんと実装されたブラウザが少ないので現時点で使い物になりません。 Indexed Databaseは、KeyValueStore形式のデータベースであり、.put()や.get()といったメソッドでJavaScriptObject表記法(JSON)のデータを保持します。 後々に、Indexed Databaseを利用するとして現段階ではWebSQLDatabaseでKeyValueStore形式のデータベースラッパーを作成して、利用法を制限しておけば、後にIndexedDatabaseの実装が普及した時にも乗り換える事が出来るようになります。 下記に、そのデータベースラッパーのコードを記載します。 ※ ChromeまたはSafariのみ対応です。 ■ローカルデータベースを利用するための前処理部分 var db = {}; db.instance = null; db.SIZE = 1024*1024*20; db.VERSION = "1.0"; db.NAME = "KRONOS DB"; db.DESCRIPTION = "kronos local database"; /** * ローカル永続化領域をオープンします。 * API内部で呼び出すので、利用者が呼び出す必要はありません。 * 初期パラメータは以下で設定可能です。 * db.SIZE db.VERSION db.NAME db.DESCRIPTION */ db.open = function() { db.instance = openDatabase(db.NAME, db.VERSION, db.DESCRIPTION , db.SIZE); // create Scheme db.instance.transaction(function(tr) { tr.executeSql("CREATE TABLE IF NOT EXISTS jsonstore ( KEY TEXT UNIQUE, VALUE TEXT ,TIMESTAMP )",[], function (data){ console.log("data" + data); console.log("CREATE TABLE SUCCESS"); }, function(){ console.log("CREATE LOCAL DB TABLE ERROR"); } ); },function(error){console.log(error);}); return db.instance; }; 上記のコードにより、db.open()メソッドをコールしたタイミングで、WebSQLDatabase上にKEYとVALUEとTIMESTAMPというそれぞれのカラムを持ったテーブルが作成されます。(既に存在すれば作成しません) ■get()メソッド /** * ローカルデータベースからキーに該当するデータを取得します。 * @param key ストアキー * @param onsuccess( json , key , timestamp ) データ取得成功時のコールバック第1引数にデータがかえってくる(第1のみ必須) * @param onerror データ取得失敗時のコールバック(省略可能) */ db.get = function(key, onsuccess, onerror) { db.onsuccess = onsuccess; db.open().transaction(function(tr) { tr.executeSql("SELECT KEY,VALUE,TIMESTAMP FROM JSONSTORE WHERE KEY = ? ;", [key], function(tr, rs) { console.log(rs); if (rs && rs.rows.length > 0) { var result = rs.rows.item(0); if (onsuccess) onsuccess(result.VALUE, result.KEY, result.TIMESTAMP); } else { if (onsuccess) onsuccess(null); } }, function(tr,error) { if (onerror) onerror(error); }); }); }; get()メソッドは、取得したいkeyとonsuccessというコールバック関数を引数にとるメソッドです。 WebSQLDatabaseにしろ、IndexedDatabaseにしろ、このような非同期型のAPIの方が、同期型API(var returndata = db.get(key);のような)よりも実装が進んでいる傾向にあります。 同期型のAPIの方がコードぱっと見たときには理解がしやすいのですが、使ってみると非同期APIの方がパフォーマンスも良く、モダンなJavaScriptコーディングには向いてると感じられます。 ■put()メソッド /** * データの登録と更新 * @param key 登録先のキー * @param object 登録するデータ * @param onsuccess(トランザクションオブジェクト, 結果オブジェクト) * @param onerror(イベントオブジェクト) データ更新時のコールバック(省略可能) * @param ondataexists データ存在時のコールバック(省略可能) */ db.put = function(key, valueText, onsuccess, onerror, ondataexists) { if($.isPlainObject(valueText)) { throw new TypeError("type error , db.put() method is not take Plain Object in valueText, call with JSON.stringify(valueText). " ); } db.open().transaction(function(tr) { tr.executeSql("SELECT KEY, VALUE FROM JSONSTORE WHERE KEY = ? ;", [key], function(tr,rs) { console.log("data put '" + key+ "'"); console.log(valueText); if (rs && rs.rows.length > 0) { var exeUpdate = true; if (ondataexists) { // データがすでに存在した場合にコールバックに渡して、 データを書き換えやUPDATE処理を実行させるかを判別する var dbValueObj = JSON.parse(rs.rows.item(0).VALUE); // 参照渡しにするためにオブジェクト化 exeUpdate = ondataexists(dbValueObj); valueText = JSON.stringify(dbValueObj); } if (exeUpdate) { // exsists tr.executeSql("UPDATE JSONSTORE set VALUE = ? , TIMESTAMP = ? WHERE KEY = ? ;", [valueText, new Date().getTime(), key] ,onsuccess ,onerror); } } else { // not exsists // put操作で更新のみ許容する場合はvalueTextに値を指定せず、ondataexistsを指定する。 if (valueText) { tr.executeSql("INSERT INTO JSONSTORE ( KEY , VALUE , TIMESTAMP ) VALUES ( ? , ? , ? );", [key, valueText, new Date().getTime()] ,onsuccess ,onerror); } } }, function(tr, error){ if (onerror) onerror(error); }); }); }; put()メソッドもコールバック関数を受け付ける非同期型のAPIとしています。 データ存在時のコールバックなど、いくつも引数がありますが多くは省略可能です。
今までのWebシステムをiPhoneやiPadでも快適につかえるようにオフライン対応できます。 |
06.モバイル関連 >