kV-Speicher – das erste integrierte Modul im Web

Browseranbieter und Web-Leistungsexperten behaupten seit dem Großteil des letzten Jahrzehnts, dass localStorage langsam ist und dass Webentwickler ihn nicht mehr verwenden sollten.

Ehrlich gesagt haben diese Leute nicht ganz unrecht. localStorage ist eine synchrone API, die den Hauptthread blockiert. Wenn Sie darauf zugreifen, kann Ihre Seite möglicherweise nicht interaktiv sein.

Das Problem ist, dass die localStorage API einfach zu verführerisch ist. Die einzige asynchrone Alternative zu localStorage ist IndexedDB, die nicht gerade für ihre Benutzerfreundlichkeit oder ihre nutzerfreundliche API bekannt ist.

Entwickler haben also die Wahl zwischen einer komplizierten und einer leistungsschwachen Lösung. Es gibt zwar Bibliotheken, die die Einfachheit der localStorage API bieten, aber asynchrone Speicher-APIs im Hintergrund verwenden. Die Einbindung einer dieser Bibliotheken in Ihre App hat jedoch Auswirkungen auf die Dateigröße und kann Ihr Leistungsbudget beeinträchtigen.

Was wäre, wenn Sie die Leistung einer asynchronen Speicher-API mit der Einfachheit der localStorage API kombinieren könnten, ohne die Kosten für die Dateigröße zu bezahlen?

Bald vielleicht. In Chrome wird eine neue Funktion namens „integrierte Module“ getestet. Das erste Modul, das wir einführen möchten, ist ein asynchrones Schlüssel/Wert-Speichermodul namens KV Storage.

Bevor ich jedoch auf die Details des KV Storage-Moduls eingehe, möchte ich erklären, was ich mit eingebauten Modulen meine.

Was sind integrierte Module?

Integrierte Module funktionieren genauso wie normale JavaScript-Module, müssen aber nicht heruntergeladen werden, da sie im Lieferumfang des Browsers enthalten sind.

Wie herkömmliche Web-APIs müssen auch integrierte Module einem Standardisierungsprozess unterzogen werden. Jedes Modul hat eine eigene Spezifikation, die eine Designüberprüfung und positive Unterstützung sowohl von Webentwicklern als auch von anderen Browseranbietern erfordert, bevor es eingeführt werden kann. In Chrome werden integrierte Module nach demselben Startvorgang implementiert und veröffentlicht wie alle neuen APIs.

Im Gegensatz zu herkömmlichen Web-APIs sind integrierte Module nicht global verfügbar, sondern nur über Importe.

Wenn Sie integrierte Module nicht global freigeben, hat das viele Vorteile: Sie verursachen keinen zusätzlichen Overhead beim Starten eines neuen JavaScript-Laufzeitkontexts (z.B. eines neuen Tabs, Workers oder Dienst-Workers) und verbrauchen weder Arbeitsspeicher noch CPU, es sei denn, sie werden tatsächlich importiert. Außerdem besteht keine Gefahr von Namenskollisionen mit anderen in Ihrem Code definierten Variablen.

Wenn Sie ein integriertes Modul importieren möchten, verwenden Sie das Präfix std: gefolgt von der Kennzeichnung des integrierten Moduls. In unterstützten Browsern können Sie das KV Storage-Modul beispielsweise mit dem folgenden Code importieren. Unten erfahren Sie, wie Sie eine KV Storage-Polyfill in nicht unterstützten Browsern verwenden.

import storage, {StorageArea} from 'std:kv-storage';

Das KV Storage-Modul

Das KV Storage-Modul ist in seiner Einfachheit der localStorage API ähnlich, aber seine API-Form ähnelt eher einer JavaScript-Map. Anstelle von getItem(), setItem() und removeItem() werden get(), set() und delete() verwendet. Außerdem gibt es andere map-ähnliche Methoden, die für localStorage nicht verfügbar sind, z. B. keys(), values() und entries(). Wie bei Map müssen die Schlüssel keine Strings sein. Sie können einen beliebigen strukturierten serialisierbaren Typ haben.

Im Gegensatz zu Map geben alle KV Storage-Methoden entweder Promises oder asynchrone Iteratoren zurück. Das liegt daran, dass dieses Modul im Gegensatz zu localStorage nicht synchron ist. Eine detaillierte Beschreibung der vollständigen API finden Sie in der Spezifikation.

Wie Sie im Codebeispiel oben vielleicht bemerkt haben, hat das KV Storage-Modul einen Standardexport storage und einen benannten Export StorageArea.

storage ist eine Instanz der Klasse StorageArea mit dem Namen 'default' und wird von Entwicklern am häufigsten in ihrem Anwendungscode verwendet. Die StorageArea-Klasse wird für Fälle bereitgestellt, in denen zusätzliche Isolation erforderlich ist (z.B. eine Drittanbieterbibliothek, die Daten speichert und Konflikte mit Daten vermeiden möchte, die über die Standard-storage-Instanz gespeichert werden). StorageArea-Daten werden in einer IndexedDB-Datenbank mit dem Namen kv-storage:${name} gespeichert. Dabei ist „kv-storage:${name}“ der Name der StorageArea-Instanz.

Hier ein Beispiel für die Verwendung des KV Storage-Moduls in Ihrem Code:

import storage from 'std:kv-storage';

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

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

Was ist, wenn ein Browser ein integriertes Modul nicht unterstützt?

Wenn Sie mit der Verwendung nativer JavaScript-Module in Browsern vertraut sind, wissen Sie wahrscheinlich, dass (zumindest bis jetzt) beim Importieren von etwas anderem als einer URL ein Fehler auftritt. std:kv-storage ist keine gültige URL.

Das wirft die Frage auf: Müssen wir warten, bis alle Browser integrierte Module unterstützen, bevor wir sie in unserem Code verwenden können? Glücklicherweise ist das nicht der Fall.

Sie können integrierte Module verwenden, sobald sie von mindestens einem Browser unterstützt werden. Das ist dank einer anderen Funktion möglich, mit der wir experimentieren: Karten importieren.

Karten importieren

Importzuordnungen sind im Wesentlichen ein Mechanismus, mit dem Entwickler Import-IDs mit einer oder mehreren alternativen IDs verknüpfen können.

Das ist sehr nützlich, da Sie so (bei Laufzeit) ändern können, wie ein Browser eine bestimmte Import-ID in Ihrer gesamten Anwendung auflöst.

Bei integrierten Modulen können Sie so in Ihrem Anwendungscode auf eine Polyfill des Moduls verweisen. Ein Browser, der das integrierte Modul unterstützt, kann diese Version stattdessen laden.

So deklarieren Sie eine Importzuordnung, damit sie mit den KV Storage-Modulen funktioniert:

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

Der wichtigste Punkt im obigen Code ist, dass die URL /path/to/kv-storage-polyfill.mjs zwei verschiedenen Ressourcen zugeordnet wird: std:kv-storage und dann noch einmal der ursprünglichen URL /path/to/kv-storage-polyfill.mjs.

Wenn der Browser also auf eine Importanweisung stößt, die auf diese URL (/path/to/kv-storage-polyfill.mjs) verweist, versucht er zuerst, std:kv-storage zu laden. Wenn das nicht funktioniert, lädt er /path/to/kv-storage-polyfill.mjs.

Der Clou dabei ist, dass der Browser weder Importkarten noch integrierte Module unterstützen muss, damit diese Methode funktioniert, da die URL, die an die Importanweisung übergeben wird, die URL für die Polyfill ist. Die polyfill ist eigentlich kein Fallback, sondern die Standardeinstellung. Das integrierte Modul ist eine progressive Verbesserung.

Was ist mit Browsern, die Module überhaupt nicht unterstützen?

Wenn Sie Importkarten verwenden möchten, um vordefinierte Module bedingt zu laden, müssen Sie import-Anweisungen verwenden. Das bedeutet auch, dass Sie Modulscripts, also <script type="module">, verwenden müssen.

Derzeit unterstützen über 80% der Browser Module. Für Browser, die das nicht tun, können Sie das Modul/Nomodule-Verfahren verwenden, um ein Legacy-Bundle bereitzustellen. Beachten Sie, dass Sie beim Generieren Ihres nomodule-Builds alle Polyfills einschließen müssen, da Sie sicher wissen, dass Browser, die keine Module unterstützen, auch keine integrierten Module unterstützen.

KV Storage-Demo

Um zu veranschaulichen, dass es möglich ist, integrierte Module zu verwenden und gleichzeitig ältere Browser zu unterstützen, habe ich eine Demo zusammengestellt, die alle oben beschriebenen Techniken umfasst und in allen aktuellen Browsern ausgeführt werden kann:

  • In Browsern, die Module, Importkarten und das integrierte Modul unterstützen, wird kein unnötiger Code geladen.
  • In Browsern, die Module und Importkarten unterstützen, aber das integrierte Modul nicht, wird die KV Storage-Polyfill über den Modul-Lademechanismus des Browsers geladen.
  • In Browsern, die Module, aber keine Importkarten unterstützen, wird die KV Storage-Polyfill auch über den Modul-Lademechanismus des Browsers geladen.
  • In Browsern, die keine Module unterstützen, wird die KV Storage-Polyfill in ihrem Legacy-Bundle (über <script nomodule> geladen) bereitgestellt.

Die Demo wird auf Glitch gehostet, sodass Sie sich den Quellcode ansehen können. Eine detaillierte Erklärung der Implementierung finden Sie in der README. Wenn Sie wissen möchten, wie sie aufgebaut ist, können Sie sich das gerne ansehen.

Wenn Sie das native integrierte Modul in Aktion sehen möchten, müssen Sie die Demo in Chrome 74 oder höher laden und die experimentelle Funktion für Webplattformen aktivieren (chrome://flags/#enable-experimental-web-platform-features).

Sie können prüfen, ob das integrierte Modul geladen wird, da das Polyfill-Script im DevTools-Quellbereich nicht angezeigt wird. Stattdessen sehen Sie die Version des integrierten Moduls. Interessant: Sie können den Quellcode des Moduls sogar prüfen oder sogar Haltestellen darin setzen:

Die KV Storage-Modulquelle in den Chrome-Entwicklertools

Bitte geben Sie uns Feedback

Diese Einführung sollte Ihnen einen Eindruck davon vermittelt haben, was mit integrierten Modulen möglich ist. Und hoffentlich bist du auch gespannt! Wir würden uns freuen, wenn Entwickler das KV Storage-Modul (sowie alle hier beschriebenen neuen Funktionen) ausprobieren und uns Feedback geben würden.

Hier sind die GitHub-Links, unter denen du uns Feedback zu den einzelnen in diesem Artikel erwähnten Funktionen geben kannst:

Wenn auf Ihrer Website derzeit localStorage verwendet wird, sollten Sie zur KV Storage API wechseln und prüfen, ob sie alle Ihre Anforderungen erfüllt. Wenn Sie sich für den Testzeitraum für KV Storage Origin registrieren, können Sie diese Funktionen bereits heute implementieren. Alle Ihre Nutzer sollten von einer besseren Speicherleistung profitieren. Nutzer von Chrome 74 und höher müssen keine zusätzlichen Downloadkosten zahlen.