WebAssembly – Webanwendungen auf der Überholspur

Seite 4: Dinge, die Wasm ausbremsen können

Inhaltsverzeichnis

Umfangreiche Daten erfordern ein Kopieren von JavaScript aus in den Speicher des Wasm-Moduls. Unter Umständen ist es notwendig, Ergebnisse zu konvertieren, bevor man sie in JavaScript verwenden kann. Das verursacht Kosten, die in einer reinen JavaScript-Anwendung nicht auftreten.

Weiter ist jeder Aufruf einer Wasm-Funktion von JavaScript aus und jeder JavaScript-Funktion von Wasm aus mit einem Kontext-Switch verbunden, der ebenfalls Zeit in Anspruch nimmt. Deshalb bietet es sich nicht an, kleine und schnell laufende Funktionen in Wasm-Module auszulagern. Da es der Wasm-Standard derzeit nicht vorsieht, Wasm-Modulen direkten Zugriff auf Web-APIs zu gestatten, müssen Anwender Zugriffe immer über Aufrufe an JavaScript-Funktionen realisieren. Das geht ebenfalls zu Lasten der Performance. Wenn es um Performance geht, sollten Web-APIs demnach im JavaScript-Teil einer Anwendung verbleiben und nur Funktionen in WebAssembly-Module realisiert werden, die keinen oder nur wenig Zugriffe auf das Document Object Model (DOM) und Web-APIs benötigen. Die WebAssembly Working Group, die den Wasm-Standard erarbeitet hat, befasst sich jedoch bereits mit der Erweiterung von WebAssembly, die einen effizienten Zugriff auf DOM und Web-APIs von WebAssembly aus gestattet.

Die Module sind häufig unnötig groß. Das kostet Bandbreite, Zeit beim Download und beim Kompilieren. Oft kompilieren Entwickler einfach viel zu viele Funktionen in Wasm-Module ein, die niemand benötigt. Meist nutzt man existierende (Standard-)Bibliotheken, die nicht auf Wasm optimiert sind, und kompiliert sie mit. Die WebAssembly-Module sind dementsprechend groß. Ein Beispiel hierfür ist C#, bei dem anfangs die ganze .NET Runtime einkompiliert wurde. Es gibt aber bereits erste Werkzeuge, die Abhilfe oder zumindest Milderung schaffen sollen. Aufgrund der statischen Struktur von Wasm-Modulen ist es relativ einfach, nicht benötigten Code aus einem Modul zu entfernen.

Wasm-Module liegen üblicherweise im Binärformat vor. Es ist auf kleine Dateien und eine schnelle Verarbeitung durch den Compiler im Browser optimiert. Der Aufbau eines Wasm-Moduls ist derart gestaltet, dass Browser sie in einem einzigen Durchlauf parsen und nach optimiertem Maschinen-Code übersetzen können. Manche Browser beginnen mit der Übersetzung während des Downloads. JavaScript hingegen gibt es nur im Textformat. Man kann es lediglich verlustfrei komprimieren, muss es dann aber im Browser wieder dekomprimieren. Bis JavaScript-Code ausgeführt wird, muss er zunächst geparst werden. In modernen Engines geschieht das zweistufig: ein Interpreter, der die initiale Ausführung übernimmt, und ein optimierender Compiler, der häufig ausgeführte Code-Pfade in Maschinen-Code übersetzt. JavaScript kann man nicht direkt in Maschinencode übersetzen, weil die Datentypen der Variablen nicht statisch, sondern dynamisch sind und sich zur Laufzeit jederzeit ändern können.

Außerdem gibt es bei WebAssembly derzeit keinen Garbage Collector. Ohne ihn muss man sich selbst um die Speicherverwaltung kümmern. Das ist heutzutage in Sprachen wie Rust mit seinen Lifetime- und Borrow-Checkern allerdings kein großes Problem mehr. Fehlt ein Garbage Collector, wird zudem keine Rechenzeit in Anspruch genommen.

Es sind bereits verschiedene Erweiterungen des Wasm-Standards in Arbeit, die auf Performance-Verbesserungen abzielen. Auf der Liste der WebAssembly Working Group stehen unter anderem Multithreading und SIMD.