Kolumne

EnterpriseTales: WebAssembly öffnet Tür ins Web

Sven Kölpin
Funktionale Programmierung

© S&S_Media

Während die Erstellung interaktiver Webanwendungen vor gar nicht allzu langer Zeit nur über Plug-ins wie Java-Applets, Flash oder Silverlight möglich waren, haben sich durch die stetige Verbesserung der Browser in den letzten Jahren rein JavaScript-basierte Anwendungen durchgesetzt. Dieser Siegeszug ist vornehmlich durch die native Einbettung der Sprache in die Browser zu begründen. Spätestens an den zahlreichen JavaScript-Sprachaufsätzen wie TypeScript oder Flow und Compile-to-JavaScript-Frameworks, beispielsweise GWT oder Vaadin, lässt sich aber unschwer erkennen, dass das alles andere als perfekt ist.

Es ist in den letzten Jahren schon fast zur Selbstverständlichkeit geworden, beliebige Programmiersprachen in JavaScript-Code zu übersetzen und den Browser so zum Kompilierungsziel für verschiedene Sprachen zu machen. Auf die Spitze getrieben wurde das mit dem asm.js-Format, auf Basis dessen in C geschriebene Programme in optimierten JavaScript-Code transpiliert und mit beeindruckender Geschwindigkeit im Browser ausgeführt werden können. Auch die Browserhersteller haben nun das Potenzial darin erkannt, das Web als natives Ziel für höhere Programmiersprachen zu deklarieren. Das Ergebnis ist der WebAssembly-Standard.

W-JAX 2019 Java-Dossier für Software-Architekten

Kostenlos: 30+ Seiten Java-Wissen von Experten

Sie finden Artikel zu EnterpriseTales, Microservices, Req4Arcs, Java Core und Angular-Abenteuer von Experten wie Uwe Friedrichsen (codecentric AG), Arne Limburg (Open Knowledge), Manfred Steyer (SOFTWAREarchitekt.at) und vielen weiteren.

 

Was ist WebAssembly?

WebAssembly (Wasm) ist ein standardisiertes, assemblerähnliches Binärformat fürs Web. Die WebAssembly-Spezifikation liegt in der Version 1.0 vor und wird bereits von allen aktuellen Browsern implementiert. Im Gegensatz zu JavaScript soll WebAssembly nicht von Hand geschrieben, sondern durch das Kompilieren höherer Sprachen wie C oder C++ automatisch erzeugt werden. Die kompilierten Binärdateien (wasm-Dateien) können als Ressourcen an die Browser ausgeliefert und dort ausgeführt werden. Durch die Nähe zu Assemblercode laufen Wasm-Module mit fast nativer Geschwindigkeit auf dem jeweiligen Zielsystem. Auch die zu übertragene Datenmenge ist, im Vergleich zu JavaScript, um ein Vielfaches geringer.

Der Browser benötigt für die Ausführung von wasm-Dateien eine gesonderte virtuelle Maschine. Die wird, genau wie die JavaScript VM, in einer Sandbox ausgeführt und kann nur auf Ressourcen zugreifen, deren Verwendung explizit von der Webplattform erlaubt und spezifiziert ist. Der Zugriff auf das Dateisystem oder auf andere sicherheitskritische Bereiche ist somit also nicht möglich.

Neben der binären Repräsentation des Assemblercodes ist auch ein textuelles Format definiert. Dieses wird in watDateien gespeichert und soll vornehmlich für Debuggingzwecke verwendet werden. Theoretisch ist es aber durchaus möglich, ganze Programme im wat-Format zu entwickeln. Vor der Ausführung müssen diese ebenfalls in das binäre wasm-Format kompiliert werden.

Die aktuelle Version des WebAssembly-Standards ist ein Minimum Viable Product (MVP), das sich bislang nur auf die Programmiersprachen C und C++ fokussiert. Das Featureset ist zudem noch stark eingeschränkt. Beispielsweise unterstützt Wasm aktuell nur vier numerische Datentypen (32- und 64-Bit-Integer sowie 32 und 64 Bit Float) und kann nicht direkt mit dem Document Object Model (DOM) oder anderen Browser-APIs interagieren. Auch weitere Funktionen, die für eine ernsthafte Integration von Managed-Memory-Programmiersprachen wie Java vonnöten sind, fehlen momentan noch. Es ist aber erklärtes Ziel, WebAssembly in zukünftigen Versionen auch für solche Sprachen besser zugänglich zu machen. So gibt es zum Beispiel bereits Vorschläge für Features wie Threading (nativ) oder Garbage Collection. Letzteres würde unter anderem auch die Erweiterung des bislang eingeschränkten Wasm-Typsystems ermöglichen.

Wie Java Applets?

Es gab schon immer Bestrebungen, Sprachen abseits von JavaScript nativ in das Web zu portieren. Zwar ist das auch bei WebAssembly die grundsätzliche Idee, allerdings sind hier die Voraussetzungen anders.

Der wichtigste Unterschied zu Plug-ins wie Flash oder Java-Applets ist, dass es sich bei WebAssembly um einen Webstandard handelt, auf den sich alle Browserhersteller geeinigt haben. Die WebAssembly VM ist deshalb, genau wie die JavaScript VM, ein fester Bestandteil der Plattform. Wasm-Module unterliegen somit nicht nur denselben Sicherheitsmechanismen wie andere Webstandards wie same-origin, sondern erlauben auch deren Nutzung. Beispielsweise ermöglicht die feste Integration der WebAssembly VM, JavaScript-Funktionen in Wasm-Modulen aufzurufen. Andersherum lassen sich auch WebAssembly-Funktionen in JavaScript verwenden. In zukünftigen Versionen wird auch ein vereinfachter Zugriff auf das DOM sowie auf die zahlreichen Browser-APIs möglich sein. Aufgrund des fehlenden Garbage Collectors ist das aktuell nur vergleichsweise umständlich realisierbar.

Der WebAssembly-Standard ist, zumindest in der Theorie, komplett unabhängig von etwaigen Programmiersprachen. Während bei Browser-Plug-ins die Sprache durch den jeweiligen Drittanbieter fest vorgegeben ist (z. B. ActionScript bei Flash oder Java bei Java-Applets), gibt es bei Wasm keinerlei Einschränkungen. Die einzige Voraussetzung ist, dass ein Compiler existiert, der die Sprache in das binäre wasm– oder textuelle wat-Format übersetzen kann.

Auf Wiedersehen, JavaScript

WebAssembly ist in der aktuellen Version nur mit der Hilfe von JavaScript verwendbar. Für die Initialisierung eines Wasm-Moduls und für Interaktionen mit dem DOM oder anderen Browser-APIs müssen JavaScript APIs genutzt werden. Ein offizielles Statement auf der WebAssembly-Seite besagt zudem, dass der Wasm-Standard nicht entwickelt wird, um JavaScript zu ersetzen. Vielmehr soll er die Webplattform vervollständigen und im Einklang mit JavaScript existieren. Das lässt sich im Übrigen auch in der Architektur wiedererkennen – die JavaScript und WebAssembly VM sind stark gekoppelt und teilen sich sogar ein Stack.

Auch zukünftige Features des WebAssembly-Standards zielen auf eine Integration der beiden Welten. Beispielsweise ist geplant, dass Wasm-Module ein Teil der ECMA-Modul-Spezifikation werden. Somit wären sie dann wie normale JavaScript-Module importierbar. Auch das Host Bindings Proposal festigt die unmittelbare Nähe zwischen WebAssembly, JavaScript und der Webplattform. Es soll die Möglichkeit schaffen, JavaScript- und DOM-Objekte direkt in Wasm zu verwenden, zu manipulieren und zu erstellen.

Dass WebAssembly und JavaScript gemeinsam die Zukunft von Webanwendungen gestalten können, zeigt sich auch am Fallbeispiel von AutoCAD. Dieses auf C++ basierende, über dreißig Jahre alte technische Zeichnungsprogramm wurde mithilfe von WebAssembly und JavaScript (React) erfolgreich in eine Webanwendung portiert. Dabei kommt Wasm für die performancekritische Applikationslogik zum Einsatz, während JavaScript zum Rendern und Interagieren mit der Benutzungsoberfläche dient. Es werden also die Stärken beider Ansätze miteinander kombiniert.

Hier wird WebAssembly helfen

Abseits davon, dass sich mit WebAssembly (zukünftig) eine beliebige Anzahl von Programmiersprachen in das Web portieren lässt, eröffnet der Standard viele weitere Möglichkeiten, die sich in drei Kategorien unterteilen lassen:

Performanz: WebAssembly kann mit fast nativer Geschwindigkeit auf dem jeweiligen Zielsystem ausgeführt werden. So ist es endlich möglich, ressourcenintensive Anwendungen – beliebte Beispiele sind hier Video- und Audioanwendungen oder Spiele – für das Web zu entwickeln. Wie bereits erwähnt, können dabei eine Kombination aus JavaScript und WebAssembly, oder sogar rein WebAssembly-basierte Ansätze verwendet werden.

Auch JavaScript-Frameworks können von der Performanz von Wasm profitieren. Beispielsweise basieren alle gängigen Single-page Application Frameworks (React, Angular, Vue, Ember) im Kern auf aufwendigen Algorithmen, die Änderungen in der Benutzungsoberfläche erkennen und diese gegebenenfalls aktualisieren können. Eine Portierung zu WebAssembly kann zu Geschwindigkeitsgewinnen der Frameworks führen. Bei Ember und Vue wird bereits aktiv an solchen Lösungen gearbeitet.

Portierbarkeit: Mit WebAssembly lassen sich Anwendungen mit überschaubaren Anpassungen in das Web portieren. Der Traum einer einheitlichen Codebasis für verschiedene Plattformen könnte so tatsächlich bald wahr werden. Zusätzlich eröffnet die Portierbarkeit für viele Applikationen ganz neue Märkte und Geschäftsmodelle. Lokale Softwareinstallationen hingegen werden zukünftig wohl immer seltener genutzt.

Auch für Entwickler bietet WebAssembly viele neue Möglichkeiten – schließlich steht nun das gesamte Ökosystem einer jeweiligen Programmiersprache auch im Web zur Verfügung. Zudem können sogar ressourcenintensive Bibliotheken problemlos im Browser eingesetzt werden, beispielsweise openCV.

Flexibilität: Die Browser liefern mittlerweile eine ganze Reihe an APIs, die Entwickler über JavaScript ansprechen können etwa Storage APIs. Diese APIs sind standardisiert und werden in enger Abstimmung mit allen Browserherstellern entworfen. Häufig nimmt der Standardisierungsprozess einiges an Zeit in Anspruch und es ist nicht festgelegt, wann ein jeweiliges API wirklich in allen Browsern zur Verfügung steht. Mithilfe von WebAssembly lässt sich dieser Prozess beschleunigen, weil nun ein einheitliches Werkzeug für die Implementierung nativer APIs zur Verfügung steht. Vielleicht wird WebAssembly die Browser-APIs auf lange Sicht sogar überflüssig machen.

Zusätzlich ermöglicht es WebAssembly zukünftig, die für ein jeweiliges Problem richtige Programmiersprache aus einem breitgefächerten Portfolio auszuwählen und trotzdem alles auf einer einzigen Plattform zu betreiben. Eine Kombination von Java, C# und C in der gleichen Webanwendungen könnte dann also keine Seltenheit sein – auch wenn bei einem solchen Zukunftsszenario die Gefahr von Wildwuchs nicht unterschätzt werden sollte.

Was bedeutet das für Java?

Zwar ist die aktuelle Version von WebAssembly in erster Linie darauf ausgelegt, mit C und C++ zu funktionieren. Dennoch gibt es schon für eine Vielzahl an anderen Sprachen erste Implementierungen. Auch für Java existieren mit JWebAssembly bereits Gehversuche. Aufgrund der erwähnten fehlenden Features ist allerdings, zumindest in der aktuellen Version von WebAssembly, nur eine eingeschränkte Teilmenge von Java verwendbar. So können in JWebAssembly nur statische Methoden und die Datentypen int, long float und double kompiliert werden. Dennoch gibt das Projekt einen guten Einblick in die Welt von morgen.

Listing 1 und Listing 2 zeigen, wie Java, WebAssembly und JavaScript gemeinsam verwendet werden können. In dem Beispiel wird die Berechnung der Summe zweier Zahlen in ein WebAssembly-Modul ausgelagert. Dieses ruft nach der Addition eine JavaScript-Funktion auf, die das Ergebnis anschließend im Browser rendert. Neben der binären wasm-Datei kann mit JWebAssembly auch die textuelle wat-Repräsentation erzeugt werden. Diese ist in Listing 3 dargestellt.

public class MyProgram {
  //export method with name "add"
  @Export(name = "add") 
  public static void add(int a, int b) {
    //add the two numbers and call the JS-function
    render(a + b);
  }
  //import JS-function with name "render"
  @Import(module = "functions", name = "render") 
  public static native void render(int current);
}
async function run() {
  const env = {
functions: {
//the render-function can be imported in WASM.
 render(result) {
  document.write(`Result from WebAssembly is ${result}`);
 }
}
  };
  //download the *.wasm-file and initialize the module.
  const wasmModule = await     
 WebAssembly.instantiateStreaming(fetch('myProgram.wasm'), env);
  //run the exported java-method
  wasmModule.instance.exports.add(41, 1);
}
;;module declaration
 (module
  ;;import JS-function
  (import "functions" "render" (func $render))
   ;;export function $add as add
  (export "add" (func $add)) 
   ;;function declaration
  (func $add (param i32) (param i32)
    ;;add first param to stack
    get_local 0
    ;;add second param to stack
    get_local 1
    ;;add the numbers on the stack
    i32.add
    ;;call the JS-function
    call $render
    return
  )
)

Fazit

WebAssembly zählt zu den aufregendsten Weiterentwicklungen der Webplattform der letzten Jahre. Mit dem Standard lassen sich viele Schwachstellen heutiger Webanwendungen adressieren. Ob sich Wasm als fester Bestandteil der Plattform etablieren wird, hängt in erster Linie von der zukünftigen Entwicklung des Standards ab. Es ist zu bezweifeln, dass JavaScript und dessen riesiges Ökosystem in absehbarer Zeit von WebAssembly verdrängt wird. Eine Co-Existenz beider Welten, in der JavaScript und Wasm gemeinsam ihre jeweiligen Stärken ausspielen können, sieht nach einem vielversprechenden Lösungsansatz für zukünftige Webanwendungen aus.

Für Java-Entwickler ist der Standard im aktuellen Zustand noch unbrauchbar. Das wird sich aber aller Voraussicht nach in den kommenden Versionen von Wasm ändern. Und dann stehen alle Türen offen.

In diesem Sinne: Stay tuned.

Geschrieben von
Sven Kölpin
Sven Kölpin
Sven Kölpin ist Enterprise Developer bei der open knowledge GmbH in Oldenburg. Sein Schwerpunkt liegt auf der Entwicklung webbasierter Enterprise-Lösungen mittels Java EE.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: