Skip to content

IndexedDB1系と2系の違いについて

IndexedDBはまだ普及していると言える段階にはありませんが、それでも開発者のフィードバックを受けてバージョンアップが行われています。最新のブラウザで実装されているのは IndexedDB2系になります。

今回は1系と2系で何が変わったのかを紹介します。

オブジェクトストアとインデックス名を変更できるようになった

db.objectStore であったり、 objectStore.index で作成済みのオブジェクトを取得し、nameメソッドで名前を変えられるようになりました。これは構造変更を伴うので、 onupgradeneeded の中で行う必要があります。

 

 

 

 

クローズ時のイベントが追加

IndexedDBを閉じた時にoncloseイベントが発火するようになりました。が、筆者環境で試す限りコールされませんでした。

 

 

 

バイナリインデックス対応

インデックスは文字列や数字だけでしたが、ArrayBufferやDataViewなどもインデックスに指定できるようになりました。

トランザクションに objectStoreNames メソッドが追加

トランザクションに、対象となっているオブジェクトストアを一覧する objectStoreNames が追加されました。通常のトランザクションであれば指定したオブジェクトストアの一覧、IndexedDBのバージョンが変わった場合には全オブジェクトストアの一覧が返ってきます。

 

 

getAll/getAllKeysの追加

対象になっているオブジェクトストアで全データを取得するgetAllと、全データのキーを取得するgetAllKeysが追加されました。

IDBKeyRange.includes の追加

IndexedDBでデータを絞り込む際に使う IDBKeyRange で、ある値が対象範囲にあるかどうかを判定する IDBKeyRange.includes が追加されました。

 

これは数値に限らず利用できます。

 

 

 

 

 

まとめ

IndexeDB 1系はEdge/IE11でも利用できます(IE11ではサポート対象外であったり、EdgetではWeb Workersの中では動かないという制限もあります)。IndexedDB 2 についてはIE/Edgeともに利用できません。実際に利用する際には、こういった点にも注意して使う必要があるでしょう。

Can I use… Support tables for HTML5, CSS3, etc

IndexedDBでデータをまとめて取得するには?

IndexedDBはWebブラウザ上で使えるJSONをサポートしたKVSです。KVSなのでデータの取得はキー単位なのですが、それだとキーを知らないとデータにアクセスできなくなりますので若干不便です。

そこで使えるのがカーソルとインデックスになります。

カーソルの使い方

カーソルはオブジェクトストアに対して openCursor メソッドで実行します。まず IndexedDB を開きます。

次にトランザクションを開き、オブジェクトストアに対して openCursor メソッドを実行します。 データはイテレーションになっており、 continue メソッドで次のデータを取得します。

すべてのデータを取得する getAll

IndexedDB2 からは全データをまとめて取得する getAll メソッドが追加されました。こちらはイテレーションではなく、すべてのデータが配列になって取得できます。大量のデータではない時にはこちらのが簡単でしょう。同じようにキーだけを取得できる getAllKeys メソッドも用意されています。

インデックスを使う

データに対してインデックスを設けている場合には、それを使ってデータを指定できます。データがnameをキーにして昇順で取得できます(0が最初)。

こちらもまた、getAllや getAllKeysが使えます。

まとめ

IndexedDBはあくまでもWebブラウザ内で使う軽量なデータベースになりますので、大量のデータを保存していることはほとんどないでしょう。そのため、openCursorを使って全データを取得したとしても遅くなるようなことはないかと思います。

なお、getAll や getAllKeysはIndexedDB2 からになり、執筆時点ではEdgeは未対応になります。

IndexedDB を使用する – Web API インターフェイス | MDN

Can I use… Support tables for HTML5, CSS3, etc

Webブラウザ上で使えるデータベース、IndexedDBを使ってみよう

Webブラウザ上でデータを保存しておくための仕組みは幾つか用意されています。

  • Cookies
  • localStorage/sessionStorage
  • IndexedDB
  • Web SQL

昔から使われているのはCookiesですが、長い文字列を保存するのには向いていません。一般的に4096バイトくらいまでとなっています。localStorageはそれよりも大きいですが、10MBくらいまでになります(localStorageは恒久、sessionStorageはセッション中のみ保存されます)。Web SQLはSQLが使える高度なデータベース機能ですが、実装がSQLiteを前提としていることで、中立性に欠けるという声もあり、開発は停止しています(via HTML5 – Web SQLデータベース)。現在は IndexedDBの利用が推奨されています。

今回は IndexedDB の使い方について紹介します。

IndexedDB の概要

IndexedDBはlocalStorageなどと同じく、キーバリュー型のストレージになります。localStorageは文字列しか保存できないのでJSONなどを保存しようと思った場合には文字列に変換する必要がありますが、 IndexedDBはJSONのまま保存できます。かといって一般的なデータベースのように検索を行える訳ではありません。

localStorageは同期型で、getItem/setItemを実行できましたが、IndexedDBは非同期型の技術になっています。また、オブジェクト(テーブル相当)をあらかじめ定義しておく必要があり、構造をバージョンという形で管理します。構造を作る際にはユニーク指定も可能です。オブジェクトの構造は自由に変えられますが、キーは定義しておく必要があります。

DBを開く

まず最初にデータベースを開きます。この時、バージョン番号を指定します(整数のみ)。このバージョン番号があがると onupgradeneeded が呼ばれますので、この際にスキーマを変更します。通常時は onsuccess が呼ばれます。

データの追加

データを追加する際には、オブジェクトストア(テーブル相当)を指定して readwrite でトランザクションを作成します。そしてオブジェクトストアに対して add を実行します。各データ追加時に onsuccess が呼ばれますが、すべての処理が完了した際には oncomplete が呼ばれます。

データの取得

データの取得は get を使います。この際には書き込みは発生しませんのでトランザクションはオブジェクトストアを指定するだけで使えます。

データの更新

データの更新を行う際にはトランザクションを readwrite で作成します。そして取得したデータに対して put を使って更新します。

データの削除

データの削除はdeleteメソッドに対してキーを指定するだけです。

まとめ

IndexedDB をそのまま使おうとすると若干の癖があります。作成、更新はオブジェクトストアが必須ですが、取得や削除は不要という処理の違いも面倒だったり、トランザクションの作成も手間に感じます。ラッピングしてくれるORM的なライブラリを使って操作するのが良さそうです。

IndexedDB 自体はlocalStorage以上に便利に使えそうなので、ぜひ活用してみてください。

Can I use… Support tables for HTML5, CSS3, etc

JavaScriptのapplyをどこで使うのか

JavaScriptの関数によっては引数を幾つでも設定できるものがあります。例えばMath.maxです。この関数は引数で与えた数字の内、最大のものを返してくれる関数です。

しかし引数を動的に変更したい場合はどうしたらいいでしょうか。そこで使えるのがapplyになります。applyは引数を配列で与えられるようになります。

最初の引数 null はthisとして何を与えるかになります。nullを与えた場合、thisはwindowオブジェクトになるようです。

自作関数で使う

自作関数の場合、多くは最後の引数をまとめたいと思うかも知れません。

このようにしておくと、最初の3つの引数(a/b/c)には値が入り、残りの引数はargsにまとまります。


引数を配列で準備しておくと、変数の定義が減るので扱いが楽になりそうです。元々配列で受け取れるようにしたり、オブジェクトで受け取ることで解決できそうですが、拡張していく中で徐々に引数が追加されてしまった場合(良くはないですが)はapplyを使えば解決できるでしょう。

PWAの技術要素について

PWA(Progressive Web App)という言葉が良く聞かれるようになってきました。今回はこのPWA全般と、各技術要素について紹介します。

PWAとは

PWAはその名の通り、Web技術の上に構築されています。PWAという技術名がある訳ではなく、幾つかの技術の組み合わせを総称してPWAと言います。

Service Worker

Service Workerはバックグラウンドで動作するJavaScriptの技術です。DOM操作はできないので、重たい処理をバックグラウンドで行ったりします。特に大事なのはキャッシュ用のリソースを取得したり、プッシュ通知を受け取る際に使われると言うことです。

リモートのリソースに対する処理において、オンライン/オフラインの判定によって処理を変えたり、同期処理にも使えます。Service WorkerはXMLHTTPRequestではなく、Fetchしか使えません。

通知

スマートフォンアプリでよく見られるプッシュ通知機能です。PWAでは二つの技術が用意されています。

Push API

Push APIはローカル通知のような機能で、クライアントサイドのJavaScriptだけで実装できます。簡単に実装できるのが魅力ですが、Webページが開かれていないと使えません。ユーザが他のタブを見ている時に新しい通知が来たことを促すといった使い方に向いています。

Notification API

アプリと同じようにリモートから送信できるプッシュ通知機能です。Service Workerを使って実装する必要があります。そのため、モダンなWebブラウザでないと使えません。

ストレージ

データを蓄積しておくストレージは主に2種類あります。

localStorage/sessionStorage

KVSとして使えます。同期型にデータを取得、更新できるので手軽です。ただし5MBくらいまでしかデータを保存できないので注意が必要です。また、保存できるのはテキスト限定で、JSONなどは文字列に変換してから保存する必要があります。

localStorageは恒久的、sessionStorageはそのセッション中だけ使えるストレージです。Cookieなどのように有効期限がないのが魅力でしょう。

IndexedDB

基本はKVSですが、インデックスを設けたりできるのでlocalStorageに比べると多少高機能です。JSONをそのまま保存できます。ただし検索したりする機能はなく、すべてのデータを取り出してフィルタする必要があります。

localStorageに比べると大きなサイズで利用できます。

HTTPS

PWAはHTTPS(localhostは除く)でしか提供できません。現在、サイトのHTTPS化は必須とも言える状態ですが、PWA化を考える上では必須になります。HTTPS自体、無料で使えるようにもなっています。セキュリティと存在証明と切り離して適用するのが良さそうです。

まとめ

PWAはスマートフォン向けの技術になります。元々ハイブリッドアプリと呼ばれるHTML5とネイティブを合わせた技術がありましたが、HTML5が高機能化するのに伴って、HTML5だけでアプリのような機能が実現できるようになってきたということでしょう。

iOSのSafariがPWA必須技術を幾つも実装していないため、率先して導入する企業は多くありませんが、今後の時流としてはPWA化が必須になってくるでしょう。

Progressive web apps – アプリセンター | MDN

パスワードレスの時代が来る!Web authentication APIの仕組みについて

Web authentication API(WebAuthnとも呼ばれます)がついにFirefox 60で対応し、本格的な普及に向けて進み始めました。Google ChromeやEdgeでも次期バージョンから対応が予定されています。残るはSafariですが、こちらは未定となっています。ただ、MacBook Proには指紋認証も付いており、iPhoneでも指紋や顔認証が付いていることを考えると将来的にはWeb authentication API互換で使えるようになることでしょう。

今回はWeb authentication APIの仕組みについて紹介します。

肝は登録と認証

パスワードレス認証を可能にするためには、二つのイベントに対応する必要があります。一つはデバイスの登録で、これはすでにログインした状態で行われる処理です。もう一つは認証で、これはデバイスがユーザに変わって入力を行います。Yubikeyのようなデバイスがよく使われますが、これはキーボードとして認識されるデバイスです。つまりユーザに変わって何かの文字列を入力しています。

公開鍵認証

Web authentication APIは公開鍵認証を使っています。また、認証された結果自体はサーバ側で処理されます。そのため、HTML5のAPIではありますが、サーバの存在が必須という点が特徴です。

登録処理について

登録処理では navigator.credentials.create() を使います。サーバとの流れをフローで描くと次のようになります。全部で6つのステップになります。

まずサーバからチャレンジ、ユーザ情報、PR(Relying party info)の3つを送ります。チャレンジ、PR辺りはOpenID 2.0で使われるものと似ているようです。そして、Webブラウザはそれらの情報に加えてクライアントのデータをAuthenticatorと呼ばれるデバイス(Yubikeyなど)に送ります。デバイスは新しい公開鍵、証明書ID、認証情報を返します(これを認証オブジェクトと呼びます)。Webブラウザは認証オブジェクトとクライアントのデータを合わせてサーバに送ります。そしてサーバで検証して完了となります。

送信する仕組みはfetchまたはXMLHTTPRequestになるようです。

認証処理について

認証処理では navigator.credentials.get() を使います。サーバの流れをフローで書くと次のようになります。全部で6つのステップになります。

まずサーバからチャレンジが送られてきます。WebブラウザではチャレンジとRP、クライアントデータのハッシュをAuthenticatorに送ります。Authenticatorでは値の検証とアサーションの作成を行います。Webブラウザには認証データと署名が送られてきます。Webブラウザは認証データと署名、そしてクライアントデータのJSONをサーバに送ります。サーバはそれらの値を検証します。

クライアントの実装デモ

Web Authentication API – Web APIs | MDNにクライアントのコードサンプルがあります。

RPはサービス名を指定しています。また、この例ではチャレンジを生成していますが、本来はサーバから送られるランダムな文字列になります。

試してみた結果

現在、一番分かりやすいデモは https://webauthn.org/ でしょう。ユーザ名だけ指定して登録し、さらにユーザ名を指定してログインできます。パスワードの入力は一切なく、認証できます。

GoogleやFacebook、DropboxなどのサイトではU2F(Universal Second Factor)にYubikeyなどが利用できます。これは多要素認証であって、ログインIDとパスワードで認証後、アプリやSMSで認証コードを送る代わりにYubikeyなどに認証コードを入力してもらう方法になります。Web authentication APIとは異なるのでご注意ください。

まとめ

Web authentication APIが流行っていけば、パスワードが不要なものになります。その結果として、パスワードが漏洩して不正アクセスを受けることもなくなります。デバイスを紛失した場合、管理画面から無効化することで安全に対応できるでしょう。また、ユーザ名などの情報と紐付けて用いますので、ユーザ名が分からない状態ではデバイスは使えないというメリットがあります。

問題はYubikeyなどが使えないスマートフォンやタブレットでしょう。iOSの指紋認証がWeb authentication APIに準拠してくれれば良いですが、アプリの認証には使えない可能性があります(SDKがリリースされれば良いですが)。そうなるとWebブラウザで認証後、コードを生成するような仕組みが必要になりそうです。また、専用デバイスが必要という点も面倒です。Web authentication APIに準拠した仕組みをデスクトップ向けのソフトウェアとスマートフォンアプリで開発すると使いやすくなりそうです。

Web Authentication API – Web APIs | MDN

PWAの根幹技術、Notifications APIの使い方

アプリでは当たり前になっているプッシュ通知ですが、Webブラウザ向けにはNotifications APIが用意されています。スマートフォンではまだ実装されていませんが、デスクトップ向けであれば十分使える状態になっています(Notifications APIはPush APIとは別です)。

今回はNotifications APIの実装方法を紹介します。

Notifications APIとPush APIの違い

Push APIはサーバからブラウザに対してプッシュ通知を送る仕組みで、Service Workerを利用します。Notifications APIはサーバサイドが不要で使えますが、Webブラウザがそのサイトを表示している時にしか使えません。

許可状態を知る

まず大事なのがユーザが通知を受け取ると許可しているかどうかです。それを調べるには Notification.permission を使います。値は3つあります。

  • default
    まだ許可を求めていません(初期値)
  • granted
    通知を許可しています
  • denied
    明確に拒否しています

そのため、deniedの時には処理を行わないというのが基本になるでしょう。

許可を得る

許可を得るのは Notification.requestPermission(); で行います。

grantedが得られれば許可を得た状態です。

通知を作成する

通知はこんな形で簡単に作成できます。

通知を閉じる

表示した通知を閉じる場合は、通知オブジェクトのcloseを使います。

通知のイベント

通知には幾つかのイベントが設定されています。

  • onclick

    通知をクリックした時に呼ばれます

  • onerror

    エラーが出た時に呼ばれます

  • onclose

    閉じた際に呼ばれます

  • onshow

    表示した時に呼ばれます

使いどころ

Notifications APIはWebページを表示している時にしか使えません。そのため、アプリのプッシュ通知のように使っていないユーザを呼び起こすのには向きません。むしろ時間がかかる処理でユーザを待たせてしまう時に完了をお知らせしたり、チャットなどで別ページを開いている時にお知らせすると言った使い方になるでしょう。

まとめ

WebSocketなどと組み合わせればサーバから通知を出したい時に命令を出すと言った使い方はできそうです。とは言え、基本的にはWebページ上で起きた変化をユーザに気付かせると言った目的で使うのが良さそうです。