Einführung in WebAssembly und seine Rolle in Node.js
\n\nWebAssembly (WASM) ist ein binäres Low-Level-Anweisungsformat, das in einer virtuellen Maschine mit nahezu nativer Leistung ausgeführt wird. Im Node.js-Ökosystem eröffnet WebAssembly neue Horizonte: Es ermöglicht die Ausführung von Code, der in C, C++, Rust oder Go geschrieben wurde, direkt in der Serverumgebung. Dies ist besonders relevant für Aufgaben, die eine hohe Leistung erfordern: Bildverarbeitung, Kryptographie, Datenparsing, Arbeit mit großen Zahlenarrays.
\n\nIn diesem Artikel behandeln wir den gesamten Arbeitszyklus mit WebAssembly in Node.js: von der Kompilierung des Quellcodes bis zur Integration des fertigen Moduls in eine JavaScript-Anwendung.
\n\nGrundlegende Konzepte und Vorbereitung der Umgebung
\n\nWas Sie vor dem Start wissen sollten
\nEin WebAssembly-Modul ist eine Binärdatei mit der Erweiterung .wasm. Es hat keinen direkten Zugriff auf das DOM oder das Dateisystem – die gesamte Interaktion erfolgt über "importierte Funktionen", die Sie aus JavaScript übergeben. In Node.js wird diese Einschränkung durch spezielle Wrapper aufgehoben.
Installation der Werkzeuge
\nZum Kompilieren von Code in WASM benötigen wir das Emscripten SDK. Installation unter Linux/macOS:
\ngit clone https://github.com/emscripten-core/emsdk.git\ncd emsdk\n./emsdk install latest\n./emsdk activate latest\nsource ./emsdk_env.sh\n\nFür Rust-Projekte verwenden Sie wasm-pack:
npm install -g wasm-pack\n\nErstellung und Kompilierung des ersten WASM-Moduls
\n\nBeispiel in C – Additionsfunktion
\nErstellen wir eine einfache Funktion in C, die zwei Zahlen addiert:
\n// math.c\n#include <emscripten.h>\n\nEMSCRIPTEN_KEEPALIVE\nint add(int a, int b) {\n return a + b;\n}\n\nEMSCRIPTEN_KEEPALIVE\nint multiply(int a, int b) {\n return a * b;\n}\n\nKompilieren in WASM mit Emscripten:
\nemcc math.c -o math.js -s EXPORTED_FUNCTIONS="['_add', '_multiply']" -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="createMathModule"\n\nAls Ergebnis erhalten wir zwei Dateien: math.wasm und math.js – einen Wrapper zum Laden.
Laden des Moduls in Node.js
\nJetzt verwenden wir das Modul in JavaScript:
\n// index.js\nconst createMathModule = require('./math.js');\n\ncreateMathModule().then(module => {\n const add = module._add;\n const multiply = module._multiply;\n\n console.log('5 + 3 =', add(5, 3)); // 8\n console.log('4 * 7 =', multiply(4, 7)); // 28\n});\n\nAusführen:
\nnode index.js\n\nArbeit mit Speicher und komplexen Datentypen
\n\nÜbergabe von Strings und Arrays
\nWASM arbeitet nur mit Zahlen. Zum Übergeben von Strings oder Arrays muss Speicher im linearen Speicher des Moduls reserviert werden. Betrachten wir ein Beispiel in C, das einen String entgegennimmt und dessen Länge zurückgibt:
\n// string_ops.c\n#include <string.h>\n#include <emscripten.h>\n\nEMSCRIPTEN_KEEPALIVE\nint string_length(char* str) {\n return strlen(str);\n}\n\nEMSCRIPTEN_KEEPALIVE\nvoid to_upper(char* str) {\n for (int i = 0; str[i]; i++) {\n if (str[i] >= 'a' && str[i] <= 'z') {\n str[i] -= 32;\n }\n }\n}\n\nKompilieren:
\nemcc string_ops.c -o string_ops.js -s EXPORTED_FUNCTIONS="['_string_length', '_to_upper']" -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="createStringModule"\n\nJavaScript-Code für die Arbeit mit dem Speicher:
\nconst createStringModule = require('./string_ops.js');\n\ncreateStringModule().then(module => {\n const { _string_length, _to_upper, heap } = module;\n \n // Speicher für den String reservieren\n const input = "hello world";\n const ptr = module._malloc(input.length + 1);\n \n // String in den WASM-Speicher kopieren\n for (let i = 0; i < input.length; i++) {\n heap[i + ptr] = input.charCodeAt(i);\n }\n heap[ptr + input.len