Die Unterstützung der
WebAssembly (Wasm) -Technologie wurde in den letzten Jahren in Browsern eingeführt. Diese Technologie kann jedoch die Funktionen des Webs erweitern und es zu einer Plattform machen, die solche Anwendungen unterstützt, die normalerweise als Desktop angesehen werden.
Das Beherrschen von WebAssembly kann für Webentwickler eine entmutigende Aufgabe sein. Der
AssemblyScript- Compiler kann die Situation jedoch verbessern.
Der Autor des Artikels, den wir in der heutigen Übersetzung veröffentlichen, erklärt zunächst, warum WebAssembly eine vielversprechende Technologie ist, und wirft anschließend einen Blick darauf, wie AssemblyScript dazu beitragen kann, das Potenzial von Wasm auszuschöpfen.
Webassembly
WebAssembly kann als einfache Sprache für Browser bezeichnet werden. Es gibt Entwicklern die Möglichkeit, Code zu erstellen, der in etwas anderem als JavaScript kompiliert wird. Auf diese Weise können die auf den Webseiten enthaltenen Programme für verschiedene Plattformen fast so schnell arbeiten wie native Anwendungen. Solche Programme werden in einer begrenzten, sicheren Umgebung ausgeführt.
Vertreter der für die Entwicklung aller führenden Browser (Chrome, Firefox, Safari und Edge) zuständigen Teams waren an der Erstellung des WebAssembly-Standards beteiligt. Sie einigten sich Anfang 2017 auf eine Systemarchitektur. Jetzt unterstützen alle oben genannten Browser WebAssembly. Tatsächlich kann diese Technologie in
ungefähr 87% der Browser verwendet werden.
WebAssembly-Code ist im Binärformat vorhanden. Dies bedeutet, dass ein solcher Code kleiner als ein ähnlicher JavaScript-Code ist und schneller geladen wird. Wasm-Code kann außerdem im
Textformat dargestellt werden , sodass die Benutzer ihn lesen und bearbeiten können.
Als der WebAssembly-Standard zum ersten Mal erschien, dachten einige Entwickler, dass er JavaScript ersetzen und die Hauptsprache des Webs werden könnte. WebAssembly wird jedoch am besten als neues Tool angesehen, das sich gut in die vorhandene Webplattform integrieren lässt. Dies ist eines seiner
vorrangigen Ziele .
Anstatt JavaScript zu ersetzen, wo diese Sprache lange und erfolgreich verwendet wurde, bietet WebAssembly neue interessante Möglichkeiten für Webentwickler. Zwar hat der Wasm-Code keinen direkten Zugriff auf das DOM, daher verwenden die meisten vorhandenen Webprojekte weiterhin JavaScript. Diese Sprache ist im Laufe der Jahre der Entwicklung und Optimierung bereits recht schnell. Und WebAssembly verfügt über eigene
Anwendungen :
- Spiele
- Wissenschaftliche Berechnungen, Visualisierungen, Simulationen.
- CAD-Anwendungen.
- Bearbeiten von Bildern und Videos.
Alle diese Verwendungszwecke von Wasm werden durch das vereinigt, was ihre jeweiligen Anwendungen normalerweise als Desktop betrachten. Aufgrund der Tatsache, dass Sie mit WebAssembly ein Leistungsniveau erreichen können, das dem von Native nahekommt, können viele ähnliche Anwendungen jetzt über die Webplattform implementiert werden.
WebAssembly kann vorhandene Webprojekte nutzen. Ein Beispiel ist das
Figma- Projekt. Dank der Wasm-Anwendung konnte die Ladezeit dieses Projekts erheblich verbessert werden. Wenn eine Website Code verwendet, der umfangreiche Berechnungen durchführt, ist es zur Verbesserung der Leistung dieser Website sinnvoll, nur diesen Code durch ein WebAssembly-Analogon zu ersetzen.
Möglicherweise möchten Sie versuchen, WebAssembly in Ihren eigenen Projekten zu verwenden. Diese Sprache kann sofort gelernt und geschrieben werden. Dennoch wurde WebAssembly ursprünglich als
Kompilierungsziel für andere Sprachen entwickelt. Es wurde mit guter Unterstützung für C und C ++ entwickelt. Wasm
experimentelle Unterstützung erschien in Go 1.11. Es wird viel Mühe darauf verwendet, Wasm-Anträge in
Rust zu schreiben.
Es ist jedoch durchaus möglich, dass Webentwickler C, C ++, Go oder Rust nicht nur zur Verwendung von WebAssembly erlernen möchten. Was machen sie? Die Antwort auf diese Frage kann AssemblyScript geben.
AssemblyScript
AssemblyScript ist ein Compiler, der TypeScript-Code in WebAssembly-Code konvertiert. TypeScript ist eine von Microsoft entwickelte Sprache. Dies ist eine Obermenge von JavaScript mit verbesserter Typunterstützung und einigen anderen Funktionen. TypeScript ist eine ziemlich
beliebte Sprache geworden. Es ist zu beachten, dass AssemblyScript nur eine begrenzte Anzahl von TypeScript-Konstrukten in Wasm konvertieren kann. Dies bedeutet, dass auch jemand, der nicht mit TypeScript vertraut ist, diese Sprache schnell auf einem Niveau erlernen kann, das ausreicht, um Code zu schreiben, den AssemblyScript versteht.
Angesichts der Tatsache, dass TypeScript JavaScript sehr ähnlich ist, können wir sagen, dass mit der AssemblyScript-Technologie Webentwickler problemlos Wasm-Module in ihre Projekte integrieren können, ohne eine komplett neue Sprache erlernen zu müssen.
Beispiel
Schreiben wir unser erstes AssemblyScript-Modul. Der gesamte Code, den wir jetzt diskutieren werden, ist auf
GitHub zu finden. Zur
Unterstützung von WebAssembly benötigen wir mindestens
Node.js 8.
Erstellen Sie ein neues Verzeichnis, initialisieren Sie das npm-Projekt und installieren Sie AssemblyScript:
mkdir assemblyscript-demo cd assemblyscript-demo npm init npm install --save-dev github:AssemblyScript/assemblyscript
Beachten Sie, dass AssemblyScript direkt vom
GitHub-Repository des Projekts installiert werden muss. AssemblyScript wurde noch nicht in npm veröffentlicht, da die Entwickler
es noch nicht für weit verbreitet halten.
Wir werden Hilfsdateien mit dem in AssemblyScript
asinit
Befehl
asinit
erstellen:
npx asinit .
Nun sollte der
package.json
unserer
package.json
die folgende Form haben:
{ "scripts": { "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug", "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized" } }
Die Datei
index.js
im Stammverzeichnis des Projekts sieht folgendermaßen aus:
const fs = require("fs"); const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm")); const imports = { env: { abort(_msg, _file, line, column) { console.error("abort called at index.ts:" + line + ":" + column); } } }; Object.defineProperty(module, "exports", { get: () => new WebAssembly.Instance(compiled, imports).exports });
Auf diese Weise können Sie WebAssembly-Module mit dem Befehl
require in Ihren Code aufnehmen. Das heißt - genauso wie normale JavaScript-Module verbunden sind.
Der
assembly
enthält die Datei
index.ts
. Der Quellcode wurde gemäß den AssemblyScript-Regeln geschrieben. Der automatisch generierte Kesselschildcode ist eine einfache Funktion zum Hinzufügen von zwei Zahlen:
export function add(a: i32, b: i32): i32 { return a + b; }
Vielleicht haben Sie erwartet, dass die Signatur einer ähnlichen Funktion wie
add(a: number, b: number): number
aussieht:
add(a: number, b: number): number
. Es würde also so aussehen, als ob es in normalem TypeScript geschrieben wäre. Hier wird jedoch anstelle der Typennummer der Typ
i32
. Dies liegt daran, dass AssemblyScript-Code bestimmte
WebAssembly-Typen für Ganzzahlen und Gleitkommazahlen verwendet und nicht den generischen Zahlentyp von TypeScript.
Lassen Sie uns das Projekt zusammenstellen:
npm run asbuild
Die folgenden Dateien sollten im
build
angezeigt werden:
optimized.wasm optimized.wasm.map optimized.wat untouched.wasm untouched.wasm.map untouched.wat
Es gibt optimierte und reguläre Versionen der Baugruppe. Jede Version der Assembly enthält eine binäre .wasm-Datei, eine
Map-Map .wasm.map und eine Textdarstellung des Binärcodes in einer .wat-Datei. Die Testpräsentation des Wasm-Codes ist für den Programmierer gedacht, aber wir werden uns diese Datei nicht einmal ansehen. Tatsächlich ist einer der Gründe für die Verwendung von AssemblyScript, dass die Arbeit mit Wasm-Code entfällt.
Führen Sie nun Node.js im REPL-Modus aus und stellen Sie sicher, dass das kompilierte Wasm-Modul auf die gleiche Weise wie jedes andere reguläre JS-Modul verwendet werden kann:
$ node Welcome to Node.js v12.10.0. Type ".help" for more information. > const add = require('./index').add; undefined > add(3, 5) 8
Im Allgemeinen ist dies alles, was für die Verwendung der WebAssembly-Technologie in Node.js erforderlich ist.
Ein Projekt mit einem Beobachter-Skript ausstatten
Um das Modul bei Änderungen während der Entwicklung automatisch neu zu
erstellen , empfehle ich die Verwendung des Pakets
onchange . Tatsache ist, dass AssemblyScript
noch kein eigenes System zur Überwachung von Dateiänderungen besitzt. Installieren Sie das onchange-Paket:
npm install --save-dev onchange
Fügen Sie
asbuild:watch
script zu
package.json
.
Das Flag -i
ist im Befehl enthalten, sodass der Erstellungsprozess einmal beim Aufrufen des Skripts gestartet wird, bevor Ereignisse auftreten.
{ "scripts": { "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug", "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", "asbuild:watch": "onchange -i 'assembly/**/*' -- npm run asbuild" } }
Anstatt den Befehl
asbuild
ständig
asbuild
, führen Sie
asbuild:watch
once.
Leistung
Wir werden einen einfachen Test schreiben, der das Leistungsniveau des Wasm-Codes bewertet. Der Hauptumfang von WebAssembly besteht darin, Aufgaben zu lösen, die den Prozessor intensiv nutzen. Dies sind zum Beispiel „schwere“ Berechnungen. Lassen Sie uns eine Funktion erstellen, die herausfindet, ob eine bestimmte Zahl eine Primzahl ist.
Die grundlegende JS-Implementierung einer ähnlichen Funktion ist unten dargestellt. Es ist sehr einfach aufgebaut, es prüft die Zahl mit roher Gewalt, aber für unsere Zwecke ist es geeignet, da es viele Berechnungen durchführt.
function isPrime(x) { if (x < 2) { return false; } for (let i = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; }
Eine ähnliche Funktion, die für den AssemblyScript-Compiler geschrieben wurde, sieht fast gleich aus. Der Hauptunterschied ist das Vorhandensein von Typanmerkungen im Code:
function isPrime(x: u32): bool { if (x < 2) { return false; } for (let i: u32 = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; }
Um die Leistung des Codes zu analysieren, verwenden wir das Paket
Benchmark.js . Installiere es:
npm install --save-dev benchmark
Erstellen Sie die Datei
benchmark.js
:
const Benchmark = require('benchmark'); const assemblyScriptIsPrime = require('./index').isPrime; function isPrime(x) { for (let i = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; } const suite = new Benchmark.Suite; const startNumber = 2; const stopNumber = 10000; suite.add('AssemblyScript isPrime', function () { for (let i = startNumber; i < stopNumber; i++) { assemblyScriptIsPrime(i); } }).add('JavaScript isPrime', function () { for (let i = startNumber; i < stopNumber; i++) { isPrime(i); } }).on('cycle', function (event) { console.log(String(event.target)); }).on('complete', function () { const fastest = this.filter('fastest'); const slowest = this.filter('slowest'); const difference = (fastest.map('hz') - slowest.map('hz')) / slowest.map('hz') * 100; console.log(`${fastest.map('name')} is ~${difference.toFixed(1)}% faster.`); }).run();
Folgendes gelang mir, nachdem ich den Befehl
node benchmark
auf meinem Computer ausgeführt hatte:
AssemblyScript isPrime x 74.00 ops/sec ±0.43% (76 runs sampled) JavaScript isPrime x 61.56 ops/sec ±0.30% (64 runs sampled) AssemblyScript isPrime is ~20.2% faster.
Wie Sie sehen, war die AssemblyScript-Implementierung des Algorithmus 20% schneller als die JS-Implementierung. Beachten Sie jedoch, dass dieser Test ein
Mikrobenchmark ist . Verlassen Sie sich nicht zu sehr auf die Ergebnisse.
Um zuverlässigere Ergebnisse der Performance-Recherche von AssemblyScript-Projekten zu erhalten, empfehle ich Ihnen, sich
dieses und
dieses Benchmark anzusehen.
Verwenden eines Wasm-Moduls auf einer Webseite
Lassen Sie uns unser Wasm-Modul auf einer Webseite verwenden. Wir beginnen mit der Erstellung einer
index.html
Datei mit folgendem Inhalt:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>AssemblyScript isPrime demo</title> </head> <body> <form id="prime-checker"> <label for="number">Enter a number to check if it is prime:</label> <input name="number" type="number" /> <button type="submit">Submit</button> </form> <p id="result"></p> <script src="demo.js"></script> </body> </html>
Erstellen Sie nun die Datei
demo.js
, deren Code unten angezeigt wird. Es gibt
viele Möglichkeiten, WebAssembly-Module
zu laden. Am effizientesten ist das Kompilieren und Initialisieren im Streaming-Modus mit der Funktion
WebAssembly.instantiateStreaming . Bitte beachten Sie, dass wir die Abbruchfunktion neu definieren müssen, die aufgerufen wird, wenn eine
Anweisung nicht ausgeführt wird.
(async () => { const importObject = { env: { abort(_msg, _file, line, column) { console.error("abort called at index.ts:" + line + ":" + column); } } }; const module = await WebAssembly.instantiateStreaming( fetch("build/optimized.wasm"), importObject ); const isPrime = module.instance.exports.isPrime; const result = document.querySelector("#result"); document.querySelector("#prime-checker").addEventListener("submit", event => { event.preventDefault(); result.innerText = ""; const number = event.target.elements.number.value; result.innerText = `${number} is ${isPrime(number) ? '' : 'not '}prime.`; }); })();
Installieren Sie als Nächstes das
Static-Server- Paket. Wir benötigen einen Server, da zur Verwendung der Funktion
WebAssembly.instantiateStreaming
das Modul mit dem MIME-Typ
application/wasm
gewartet werden muss.
npm install --save-dev static-server
Fügen Sie das entsprechende Skript zu
package.json
:
{ "scripts": { "serve-demo": "static-server" } }
npm run serve-demo
Befehl
npm run serve-demo
und öffnen Sie die lokale Host-URL im Browser. Wenn Sie eine bestimmte Zahl in das Formular eingeben, können Sie herausfinden, ob es einfach ist oder nicht. Bei der Entwicklung von AssemblyScript haben wir den Weg vom Schreiben von Code zur Verwendung in Node.js und auf einer Webseite weit zurückgelegt.
Zusammenfassung
WebAssembly und damit auch AssemblyScript können Websites nicht auf magische Weise beschleunigen. Aber Wasm wurde nie beauftragt, absolut alles zu beschleunigen. Diese Technologie ist insofern bemerkenswert, als sie den Zugang zum Internet für neue Arten von Anwendungen eröffnet.
Ähnliches gilt für AssemblyScript. Diese Technologie vereinfacht den Zugriff auf WebAssembly für eine große Anzahl von Entwicklern. Wenn Sie Code in einer Sprache in der Nähe von JavaScript erstellen, können Sie mit den Funktionen von WebAssembly komplexe Rechenprobleme lösen.
Sehr geehrte Leser! Wie beurteilen Sie die Aussichten für die Verwendung von AssemblyScript in Ihren Projekten?
