Hochleistungsspeicher für Ihre Anwendung: die Storage Foundation API

Die Webplattform bietet Entwicklern zunehmend die Tools, die sie benötigen, um leistungsstarke Anwendungen für das Web zu erstellen. Vor allem WebAssembly (Wasm) hat die Tür zu schnellen und leistungsstarken Webanwendungen geöffnet, während Technologien wie Emscripten es Entwicklern ermöglichen, bewährten Code im Web wiederzuverwenden. Damit Entwickler dieses Potenzial wirklich nutzen können, müssen sie in Bezug auf den Speicher dieselben Möglichkeiten und dieselbe Flexibilität haben.

Hier kommt die Storage Foundation API ins Spiel. Die Storage Foundation API ist eine neue schnelle und neutrale Speicher-API, die neue und häufig gewünschte Anwendungsfälle für das Web ermöglicht, z. B. die Implementierung leistungsstarker Datenbanken und die ordnungsgemäße Verwaltung großer temporärer Dateien. Mit dieser neuen Schnittstelle können Entwickler ihren eigenen Speicher ins Web bringen und so die Funktionslücke zwischen Web- und plattformspezifischem Code verringern.

Die Storage Foundation API ist so konzipiert, dass sie einem sehr einfachen Dateisystem ähnelt. Sie bietet Entwicklern Flexibilität, da sie generische, einfache und leistungsstarke Primitiven bereitstellt, auf denen sie Komponenten höherer Ebene aufbauen können. Anwendungen können das beste Tool für ihre Anforderungen nutzen und so die richtige Balance zwischen Nutzerfreundlichkeit, Leistung und Zuverlässigkeit finden.

Warum braucht das Web eine weitere Speicher-API?

Die Webplattform bietet Entwicklern eine Reihe von Speicheroptionen, die jeweils für bestimmte Anwendungsfälle entwickelt wurden.

  • Einige dieser Optionen überschneiden sich nicht mit diesem Vorschlag, da sie nur die Speicherung sehr kleiner Datenmengen zulassen, z. B. Cookies oder die Web Storage API, die aus den Mechanismen sessionStorage und localStorage besteht.
  • Andere Optionen sind bereits aus verschiedenen Gründen veraltet, z. B. die File and Directory Entries API oder WebSQL.
  • Die File System Access API hat eine ähnliche API-Oberfläche, wird aber verwendet, um mit dem Dateisystem des Clients zu interagieren und Zugriff auf Daten zu ermöglichen, die sich möglicherweise außerhalb des Ursprungs oder sogar des Browsers befinden. Dieser andere Fokus geht mit strengeren Sicherheitsanforderungen und höheren Leistungskosten einher.
  • Die IndexedDB API kann als Backend für einige Anwendungsfälle der Storage Foundation API verwendet werden. Emscripten enthält beispielsweise IDBFS, ein auf IndexedDB basierendes persistentes Dateisystem. Da IndexedDB jedoch im Grunde ein Schlüssel-Wert-Speicher ist, sind die Leistungsbeschränkungen erheblich. Außerdem ist der direkte Zugriff auf Unterabschnitte einer Datei unter IndexedDB noch schwieriger und langsamer.
  • Schließlich wird die CacheStorage-Schnittstelle weitgehend unterstützt und ist für die Speicherung großer Datenmengen wie Webanwendungsressourcen optimiert. Die Werte sind jedoch unveränderlich.

Die Storage Foundation API soll alle Lücken der bisherigen Speicheroptionen schließen, indem sie die leistungsstarke Speicherung veränderlicher großer Dateien ermöglicht, die im Ursprung der Anwendung definiert sind.

Vorgeschlagene Anwendungsfälle für die Storage Foundation API

Beispiele für Websites, die diese API verwenden können:

  • Produktivitäts- oder Kreativitäts-Apps, die große Mengen an Video-, Audio- oder Bilddaten verarbeiten. Solche Apps können Segmente auf die Festplatte auslagern, anstatt sie im Arbeitsspeicher zu behalten.
  • Apps, die auf ein nichtflüchtiges Dateisystem angewiesen sind, auf das über Wasm zugegriffen werden kann, und die mehr Leistung benötigen, als IDBFS garantieren kann.

Was ist die Storage Foundation API?

Die API besteht aus zwei Hauptteilen:

  • Dateisystemaufrufe, die grundlegende Funktionen für die Interaktion mit Dateien und Dateipfaden bieten.
  • Dateihandles, die Lese- und Schreibzugriff auf eine vorhandene Datei ermöglichen.

Dateisystemaufrufe

Mit der Storage Foundation API wird ein neues Objekt eingeführt, storageFoundation, das sich im window-Objekt befindet und eine Reihe von Funktionen umfasst:

  • storageFoundation.open(name): Öffnet die Datei mit dem angegebenen Namen, sofern sie vorhanden ist, und erstellt andernfalls eine neue Datei. Gibt ein Promise zurück, das mit der geöffneten Datei aufgelöst wird.
  • storageFoundation.delete(name): Entfernt die Datei mit dem angegebenen Namen. Gibt ein Promise zurück, das aufgelöst wird, wenn die Datei gelöscht wird.
  • storageFoundation.rename(oldName, newName): Benennt die Datei atomar vom alten in den neuen Namen um. Gibt ein Promise zurück, das aufgelöst wird, wenn die Datei umbenannt wird.
  • storageFoundation.getAll(): Gibt ein Promise zurück, das mit einem Array aller vorhandenen Dateinamen aufgelöst wird.
  • storageFoundation.requestCapacity(requestedCapacity): Fordert neue Kapazität (in Byte) für die Verwendung durch den aktuellen Ausführungskontext an. Gibt ein Promise zurück, das mit dem verbleibenden Betrag der verfügbaren Kapazität aufgelöst wird.
  • storageFoundation.releaseCapacity(toBeReleasedCapacity): Gibt die angegebene Anzahl von Byte aus dem aktuellen Ausführungskontext frei und gibt ein Promise zurück, das mit der verbleibenden Kapazität aufgelöst wird.
  • storageFoundation.getRemainingCapacity(): Gibt ein Promise zurück, das mit der für den aktuellen Ausführungskontext verfügbaren Kapazität aufgelöst wird.

Dateihandles

Die Arbeit mit Dateien erfolgt über die folgenden Funktionen:

  • NativeIOFile.close(): Schließt eine Datei und gibt ein Promise zurück, das aufgelöst wird, wenn der Vorgang abgeschlossen ist.
  • NativeIOFile.flush(): Synchronisiert (d. h. leert) den In-Memory-Status einer Datei mit dem Speichergerät und gibt ein Promise zurück, das aufgelöst wird, wenn der Vorgang abgeschlossen ist.
  • NativeIOFile.getLength(): Gibt ein Promise zurück, das mit der Länge der Datei in Byte aufgelöst wird.
  • NativeIOFile.setLength(length): Legt die Länge der Datei in Byte fest und gibt ein Promise zurück, das aufgelöst wird, wenn der Vorgang abgeschlossen ist. Wenn die neue Länge kleiner als die aktuelle Länge ist, werden Bytes ab dem Ende der Datei entfernt. Andernfalls wird die Datei mit Bytes mit dem Wert „0“ erweitert.
  • NativeIOFile.read(buffer, offset): Liest den Inhalt der Datei am angegebenen Offset über einen Puffer, der das Ergebnis der Übertragung des angegebenen Puffers ist. Dieser wird dann getrennt. Gibt ein NativeIOReadResult mit dem übertragenen Puffer und der Anzahl der Byte zurück, die erfolgreich gelesen wurden.

    Ein NativeIOReadResult ist ein Objekt, das aus zwei Einträgen besteht:

    • buffer: Ein ArrayBufferView, das das Ergebnis der Übertragung des an read() übergebenen Puffers ist. Er hat denselben Typ und dieselbe Länge wie der Quellpuffer.
    • readBytes: Die Anzahl der Byte, die erfolgreich in buffer gelesen wurden. Das kann weniger als die Puffergröße sein, wenn ein Fehler auftritt oder der Lesebereich über das Ende der Datei hinausgeht. Sie wird auf null gesetzt, wenn der Lesebereich über das Ende der Datei hinausgeht.
  • NativeIOFile.write(buffer, offset): Schreibt den Inhalt des angegebenen Puffers in die Datei am angegebenen Offset. Der Puffer wird übertragen, bevor Daten geschrieben werden, und bleibt daher getrennt. Gibt ein NativeIOWriteResult mit dem übertragenen Puffer und der Anzahl der Bytes zurück, die erfolgreich geschrieben wurden. Die Datei wird erweitert, wenn der Schreibbereich ihre Länge überschreitet.

    Ein NativeIOWriteResult ist ein Objekt, das aus zwei Einträgen besteht:

    • buffer: Ein ArrayBufferView, das das Ergebnis der Übertragung des an write() übergebenen Puffers ist. Er hat denselben Typ und dieselbe Länge wie der Quellpuffer.
    • writtenBytes: Die Anzahl der Byte, die erfolgreich in buffer geschrieben wurden. Das kann bei einem Fehler weniger als die Puffergröße sein.

Vollständige Beispiele

Damit die oben eingeführten Konzepte klarer werden, finden Sie hier zwei vollständige Beispiele, die Sie durch die verschiedenen Phasen im Lebenszyklus von Storage Foundation-Dateien führen.

Öffnen, Schreiben, Lesen, Schließen

// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
  // Request 100 bytes of capacity for this context.
  await storageFoundation.requestCapacity(100);

  const writeBuffer = new Uint8Array([64, 65, 66]);
  // Write the buffer at offset 0. After this operation, `result.buffer`
  // contains the transferred buffer and `result.writtenBytes` is 3,
  // the number of bytes written. `writeBuffer` is left detached.
  let result = await file.write(writeBuffer, 0);

  const readBuffer = new Uint8Array(3);
  // Read at offset 1. `result.buffer` contains the transferred buffer,
  // `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
  // detached.
  result = await file.read(readBuffer, 1);
  // `Uint8Array(3) [65, 66, 0]`
  console.log(result.buffer);
} finally {
  file.close();
}

Öffnen, auflisten, löschen

// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();

Sicherheit und Berechtigungen

Das Chromium-Team hat die Storage Foundation API unter Berücksichtigung der in Controlling Access to Powerful Web Platform Features definierten Grundsätze entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie.

Wie bei anderen modernen Speicher-APIs im Web ist der Zugriff auf die Storage Foundation API an den Ursprung gebunden. Das bedeutet, dass ein Ursprung nur auf selbst erstellte Daten zugreifen kann. Außerdem ist sie auf sichere Kontexte beschränkt.

Kontrolle durch Nutzer

Das Speicherkontingent wird verwendet, um den Zugriff auf Speicherplatz zu verteilen und Missbrauch zu verhindern. Arbeitsspeicher, den Sie belegen möchten, muss zuerst angefordert werden. Wie bei anderen Speicher-APIs können Nutzer den von der Storage Foundation API belegten Speicherplatz über ihren Browser löschen.

Nützliche Links

Danksagungen

Die Storage Foundation API wurde von Emanuel Krivoy und Richard Stotz spezifiziert und implementiert. Dieser Artikel wurde von Pete LePage und Joe Medley geprüft.

Hero-Image von Markus Spiske auf Unsplash.