LoginSignup
6

More than 3 years have passed since last update.

ブラウザの新しいstorage moduleのKV Storageを試してみた!

Last updated at Posted at 2019-03-31

参考・関連リンク

注意

記事の内容に間違いなどありましたらご指摘お願いします:bow:

KV Storageとは

ブラウザベンダやWebパフォーマンスの専門家は、この10年間の大部分でlocalStorageは動作が遅く、Web開発者はそれを使うのをやめるべきだと言ってきました。

公平に言うと、これを言っている人々は間違っていません。 localStorageは、メインスレッドをブロックする同期APIです。アクセスするたびに、ページがインタラクティブに表示されなくなる可能性があります。

問題は、localStorage APIが非常に単純で、localStorageの唯一の非同期的な代替方法がIndexedDBであることです。これは(使いやすさや使いやすさのために知られていません)。

そのため、開発者は使いにくいものとパフォーマンスに悪いもののどちらかを選択できます。そして、実際には非同期ストレージAPIを実際に使用しながらlocalStorage APIのシンプルさを提供するライブラリもありますが、その中にはファイルサイズのコストがかかり、パフォーマンスの予算を浪費する可能性があります。

しかし、ファイルサイズのコストを支払う必要なしに、localStorage APIの単純さで非同期ストレージAPIのパフォーマンスを得ることが可能だったらどうでしょうか。

まあ、すぐにあるかもしれません。 Chromeは組み込みモジュールと呼ばれる新機能を試しています。最初に出荷する予定の機能は、KV Storageという非同期のキー/値ストレージモジュールです。

localStorageと違い非同期で、かつ簡単に扱える、KV Storage (Key-Value型データベース)の機能のようです。

動くサンプル

chromeのバージョン73だと動かすことができません。※2019/03/31現在

Note: The KV Storage module is currently available in Chrome 74 if you have the experimental web platform features flag turned on: (chrome://flags/#enable-experimental-web-platform-features).

image.png

参考ページにある通りに、実験用Webプラットフォーム機能フラグをonにすると動かすことができたので、この記事ではその状態で試していきます。

chrome://flags/#enable-experimental-web-platform-features

こちらを Enabled にしてchromeを再起動する

image.png

ほぼ参考ページのサンプル通りですが、このように簡単に動かすことができました

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script type="module">
        import { storage } from "std:kv-storage";

        (async () => {
            const oldPreferences = await storage.get("preferences");

            document.querySelector("form").addEventListener("submit", async e => {
                e.preventDefault();
                const newPreferences = Object.assign({}, oldPreferences, {
                    date: new Date().toLocaleString()
                });

                await storage.set("preferences", newPreferences);
                console.log(await storage.get("preferences"));
            });
        })();
    </script>
</head>
<body>
    <form><input type="submit"></form>
</body>
</html>

image.png

ブラウザ対応

polyfillを使う

$ npm i kv-storage-polyfill

参考ページの通りだとこういう書き方になるようです

コードはこちらにも用意しました

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <script type="importmap">
    {
        "imports": {
            "/node_modules/kv-storage-polyfill/dist/kv-storage-polyfill.mjs": [
                "std:kv-storage",
                "/node_modules/kv-storage-polyfill/dist/kv-storage-polyfill.mjs"
            ]
        }
    }
    </script>

    <script type="module">
        import { storage } from '/node_modules/kv-storage-polyfill/dist/kv-storage-polyfill.mjs';

        (async () => {
            const oldPreferences = await storage.get('preferences');

            document.querySelector('form').addEventListener('submit', async e => {
                e.preventDefault();
                const newPreferences = Object.assign({}, oldPreferences, {
                    date: new Date().toLocaleString()
                });

                await storage.set('preferences', newPreferences);
                console.log(await storage.get('preferences'));
            });
        })();
    </script>
</head>
<body>
    <form><input type="submit"></form>
</body>
</html>

参考:https://github.com/WICG/import-maps#for-built-in-modules-in-browsers-without-import-maps

参考に書いてあることのまんまですが、以下のように動作してくれるとのことです

  • importmapをサポートしていないブラウザはpolyfillを受け取ります
  • importmapをサポートしているがKV Storageをサポートしていないブラウザは、polifillのURLからそれ自体へのマッピングになるので、polifillを受け取ります
  • importmapとKV Storageの両方をサポートするブラウザは、polyfill URLからstd:kv-storageへのマッピングになるため、組み込みモジュールを受け取ります

polyfillを使うことで、Safariでも動作することが確認できました

image.png

API

※以下を参考にいくつか試してみました、詳細知りたい方は以下を参考にしてください:bow:

基本的な使い方

    <script type="module">
        import { storage } from "std:kv-storage";

        (async () => {
            console.log(await storage.get("category")) // undefind
            await storage.set("category", "hoge"); // 値をセット
            console.log(await storage.get("category")) // hoge
            await storage.delete("category"); // 値を削除
            console.log(await storage.get("category")) // undefind

            await storage.set("foo", 1);
            await storage.set("bar", 2);
            for await (const [key, value] of storage.entries()) {
                console.log(key, value); // 「foo 1」「bar 2」がそれぞれ出力
            }
            await storage.clear() // 全て削除
            console.log(await storage.get("foo")) // undefind
            console.log(await storage.get("bar")) // undefind
        })();
    </script>

image.png

new StorageArea()

new StorageArea とすることで、データをそこに保存することができます。
キー名が衝突する可能性が低くなります

    <script type="module">
        import { storage, StorageArea } from "std:kv-storage";

        (async () => {
            await storage.set("mycat", "Tom");
            console.assert(await storage.get("mycat") === "Tom");

            const otherStorage = new StorageArea("unique string");
            console.assert(await otherStorage.get("mycat") === undefined);
            await otherStorage.set("mycat", "Jerry");
            console.assert(await otherStorage.get("mycat") === "Jerry");
        })();
    </script>

最後まで読んでいただいてありがとうございましたm(_ _)m

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
6