V tomto, čtvrtém díle našeho seriálu o WebAssembly pro začátečníky, se důkladně zaměříme na interakci mezi WebAssembly a JavaScriptem.
Podrobně si ukážeme, jak integrovat WebAssembly do vašeho JavaScriptového kódu. Navíc prozkoumáme WebAssembly JavaScript API a jeho možnosti.
WebAssembly je otevřený standard reprezentovaný binárním formátem. Umožňuje vývojářům spouštět aplikace v prohlížečích s výkonem blízkým nativnímu. Pokud jste se s tímto konceptem dosud nesetkali, doporučujeme vám prostudovat si předchozí části našeho průvodce.
Pojďme se do toho pustit.
Integrace WebAssembly s JavaScriptem
V prvním díle našeho seriálu o WebAssembly jsme si objasnili, jak WASM funguje. Pro tvorbu vysoce výkonného kódu pro vaši webovou aplikaci je nezbytné využít rozhraní WASM API a funkce dostupné v JavaScriptu. Stejně tak jsme si uvedli, jak mohou JavaScriptové frameworky využívat WASM k vytváření aplikací s excelentním výkonem.
V současnosti bohužel nelze moduly WASM načítat jako ES6 moduly pomocí <script type="module">
. Právě zde nastupuje JavaScript. Umožňuje načítání a kompilaci WASM v prohlížeči. Konkrétní postup je uveden níže:
- Načtěte bajty .wasm do objektu ArrayBuffer nebo typovaného pole.
- Pro kompilaci bajtů použijte
WebAssembly.Module
. - Následně vytvořte instanci
WebAssembly.Module
s importy pro získání exportů s možností volání.
Je tedy nutné začít s předkompilovaným modulem WASM. Zde máte k dispozici několik možností. Pro napsání kódu a jeho následnou transformaci do modulu .wasm můžete využít Rust, C/C++, AssemblyScript a dokonce i TinyGo(Go).
WebAssembly je technicky cílem kompilace pro různé programovací jazyky. To znamená, že napíšete kód ve zvoleném jazyce a následně v aplikaci (webové či jiné) použijete vygenerovaný binární kód. V případě použití na serverech bude nutné použít WASI pro interakci se systémy.
Vzhledem k tomu, že WebAssembly využívá lineární paměť prostřednictvím rozšiřitelného pole, jak JavaScript, tak WASM k ní mají synchronní přístup. To vám dává možnost vytvářet rychlé a funkčně bohaté aplikace.
Příklady použití WebAssembly a JavaScriptu
Použijme praktické příklady, abychom si ukázali, jak lze efektivně využívat WASM s JavaScriptem.
Jak již bylo zmíněno, je potřeba mít předkompilovaný modul WASM. V tomto příkladě použijeme Emscripten (C/C++). Díky tomu, že WASM poskytuje vysoce výkonný binární formát, můžeme vygenerovaný kód spustit společně s JavaScriptem nebo jinými jazyky.
Nastavení vývojového prostředí
Protože budeme pracovat s Emscripten, potřebujeme si nainstalovat nástroj emsdk. Ten vám umožní zkompilovat váš C/C++ kód do .wasm formátu.
V terminálu jednoduše spusťte následující příkaz. Pokud nemáte nainstalovaný GIT, podívejte se na náš průvodce Open Source 101: Systém správy verzí a Git.
git clone https://github.com/emscripten-core/emsdk.git cd emsdk
#Output [email protected]:~/Projects/WASM2$ git clone https://github.com/emscripten-core/emsdk.git Cloning into 'emsdk'... remote: Enumerating objects: 3566, done. remote: Counting objects: 100% (62/62), done. remote: Compressing objects: 100% (49/49), done. remote: Total 3566 (delta 31), reused 38 (delta 13), pack-reused 3504 Receiving objects: 100% (3566/3566), 2.09 MiB | 2.24 MiB/s, done. Resolving deltas: 100% (2334/2334), done. [email protected]:~/Projects/WASM2$ cd emsdk [email protected]:~/Projects/WASM2/emsdk$
V adresáři emdsk vyvoláme další příkaz pro získání nejnovější verze Emscripten připravené k použití.
To provedete spuštěním následujících příkazů.
./emsdk install latest ./emsdk activate latest source ./emsdk_env.sh
#Output [email protected]:~/Projects/WASM2/emsdk$ ./emsdk install latest Resolving SDK alias 'latest' to '3.1.31' Resolving SDK version '3.1.31' to 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit' Installing SDK 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'.. Installing tool 'node-14.18.2-64bit'.. Downloading: /home/nitt/Projects/WASM2/emsdk/zips/node-v14.18.2-linux-x64.tar.xz from https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz, 21848416 Bytes Unpacking '/home/nitt/Projects/WASM2/emsdk/zips/node-v14.18.2-linux-x64.tar.xz' to '/home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit' Done installing tool 'node-14.18.2-64bit'. Installing tool 'releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'.. Downloading: /home/nitt/Projects/WASM2/emsdk/zips/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-wasm-binaries.tbz2 from https://storage.googleapis.com/webassembly/emscripten-releases-builds/linux/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a/wasm-binaries.tbz2, 349224945 Bytes Unpacking '/home/nitt/Projects/WASM2/emsdk/zips/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-wasm-binaries.tbz2' to '/home/nitt/Projects/WASM2/emsdk/upstream' Done installing tool 'releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'. Done installing SDK 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'. [email protected]:~/Projects/WASM2/emsdk$ ./emsdk activate latest Resolving SDK alias 'latest' to '3.1.31' Resolving SDK version '3.1.31' to 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit' Setting the following tools as active: node-14.18.2-64bit releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit Next steps: - To conveniently access emsdk tools from the command line, consider adding the following directories to your PATH: /home/nitt/Projects/WASM2/emsdk /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin /home/nitt/Projects/WASM2/emsdk/upstream/emscripten - This can be done for the current shell by running: source "/home/nitt/Projects/WASM2/emsdk/emsdk_env.sh" - Configure emsdk in your shell startup scripts by running: echo 'source "/home/nitt/Projects/WASM2/emsdk/emsdk_env.sh"' >> $HOME/.bash_profile
Poslední příkaz, source ./emsdk_env.sh
, zajistí nastavení cesty k nástroji emcc Emscripten a umožňuje jeho využití pro kompilaci kódu.
#Output [email protected]:~/Projects/WASM2/emsdk$ source ./emsdk_env.sh Setting up EMSDK environment (suppress these messages with EMSDK_QUIET=1) Adding directories to PATH: PATH += /home/nitt/Projects/WASM2/emsdk PATH += /home/nitt/Projects/WASM2/emsdk/upstream/emscripten PATH += /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin Setting environment variables: PATH = /home/nitt/Projects/WASM2/emsdk:/home/nitt/Projects/WASM2/emsdk/upstream/emscripten:/home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin EMSDK = /home/nitt/Projects/WASM2/emsdk EMSDK_NODE = /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin/node [email protected]:~/Projects/WASM2/emsdk$
Nyní vygenerujeme wasm kód spuštěním následujícího příkazu.
emcc hello-etechblog.cz.c -o hello-etechblog.cz.js
#Output [email protected]:~/Projects/WASM2$ emcc hello-etechblog.cz.c -o hello-etechblog.cz.js shared:INFO: (Emscripten: Running sanity checks) cache:INFO: generating system asset: symbol_lists/1c683af19e290d0b5ca7a8747d74a76f63dcb362.txt... (this will be cached in "/home/nitt/Projects/WASM2/emsdk/upstream/emscripten/cache/symbol_lists/1c683af19e290d0b5ca7a8747d74a76f63dcb362.txt" for subsequent builds) cache:INFO: - ok [email protected]:~/Projects/WASM2$ dir emsdk hello-etechblog.cz.c hello-etechblog.cz.js hello-etechblog.cz.wasm [email protected]:~/Projects/WASM2$
Jak vidíte, výsledkem jsou soubory hello-etechblog.cz.js
a hello-etechblog.cz.wasm
. Pro ověření můžete použít příkaz dir v adresáři projektu.
Oba tyto soubory jsou nezbytné. Soubor hello-etechblog.cz.wasm
obsahuje zkompilovaný kód. Soubor hello-etechblog.cz.js
obsahuje JavaScript potřebný pro spuštění. Protože Emscripten podporuje jak webové, tak Node.js prostředí, můžeme to otestovat pomocí Node.
node hello-etechblog.cz.js
#Output [email protected]:~/Projects/WASM2$ node hello-etechblog.cz.js Hello, etechblog.cz! [email protected]:~/Projects/WASM2$
Chcete-li si ověřit, jak to běží na webu, můžete pomocí Emscripten vygenerovat HTML soubor. Pro to spusťte následující příkaz.
emcc hello-etechblog.cz.c -o hello-etechblog.cz.html
#Output [email protected]:~/Projects/WASM2$ emcc hello-etechblog.cz.c -o hello-etechblog.cz.html [email protected]:~/Projects/WASM2$
Pro spuštění HTML souboru můžete využít Python 3 HTTPServer pomocí následujícího příkazu.
python3 -m http.server 8000
Nyní přejděte na http://localhost:8000/hello-etechblog.cz.html
a podívejte se na výstup.
Poznámka: Většina systémů má Python předinstalovaný. Pokud ne, můžete jej snadno nainstalovat, než se pokusíte spustit Python 3 server.
Využití JavaScript API pro práci s WASM
V této sekci se blíže podíváme na JavaScript WASM API. S jeho pomocí se naučíme, jak načíst WASM kód a následně jej spustit. Nejprve se však podívejme na následující kód:
fetch('hello-etechblog.cz.wasm').then( response => response.arrayBuffer()) .then (bytes => WebAssembly.instantiate(bytes)) .then(result=> alert(result.instance.exports.answer()))
Výše uvedený kód využívá následující JavaScript API:
- fetch() prohlížeče
- WebAssembly.instantiate
Kromě těchto existují i další API, které stojí za zmínku. Patří mezi ně:
- WebAssembly.compile
- WebAssembly.instance
- WebAssembly.instantiate
- WebAssembly.instantiateStreaming
fetch() API prohlížeče
Rozhraní fetch() API načítá .wasm síťový zdroj. Pokud se ho pokoušíte načíst lokálně, musíte zrušit sdílení zdrojů mezi různými doménami, aby se síťový zdroj načetl. Jinak to za vás může provést uzlový server. Pro instalaci a spuštění uzlového serveru spusťte následující příkaz:
sudo apt install npm
Následně spusťte server pomocí následujícího příkazu:
npx http-server -o
#Output http-server version: 14.1.1 http-server settings: CORS: disabled Cache: 3600 seconds Connection Timeout: 120 seconds Directory Listings: visible AutoIndex: visible Serve GZIP Files: false Serve Brotli Files: false Default File Extension: none Available on: http://127.0.0.1:8080 http://192.168.0.107:8080 Hit CTRL-C to stop the server Open: http://127.0.0.1:8080 [2023-01-28T19:22:21.137Z] "GET /" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70" (node:37919) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated (Use `node --trace-deprecation ...` to show where the warning was created) [2023-01-28T19:22:21.369Z] "GET /favicon.ico" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70" [2023-01-28T19:22:21.369Z] "GET /favicon.ico" Error (404): "Not found"
Otevře se webový prohlížeč, kde uvidíte všechny soubory projektu.
Nyní otevřete hello-etechblog.cz.html
a spusťte vývojářské nástroje webu. V konzoli zadejte následující:
fetch(“hello-etechblog.cz.wasm”);
Výsledkem bude slib, jak je uvedeno níže:
#Output Promise {<pending>} [[Prototype]]: Promise [[PromiseState]]: "fulfilled" [[PromiseResult]]: Response body: (...) bodyUsed: false headers: Headers {} ok: true redirected: false status: 200 statusText: "OK" type: "basic" url: "http://127.0.0.1:8080/hello-etechblog.cz.wasm" [[Prototype]]: Response
Můžete také napsat následující skript a spustit ho prostřednictvím HTML.
Pro spuštění WASM modulů na serveru použijte následující kód v Node.js:
const fs = require('fs'); const run = async() => { const buffer = fs.readFileSync("./hello-etechblog.cz.wasm"); const result = await WebAssembly.instantiate(buffer); console.log(result.instance.exports.answer()); }; run();
Pro hlubší pochopení WebAssembly JavaScript API vám doporučujeme prostudovat si oficiální dokumentaci.
JavaScript vs. WASM
Pro pochopení vztahu mezi WASM a JavaScriptem je musíme také porovnat. WASM je rychlejší a používá binární formát pro cílovou kompilaci, zatímco JavaScript je jazyk na vysoké úrovni. Binární kód WASM se obtížněji učí, existují však způsoby, jak s WASM efektivně pracovat.
Klíčové rozdíly mezi WASM a JavaScriptem zahrnují následující:
- WASM je kompilovaný jazyk, zatímco JS je interpretovaný. Prohlížeč musí JavaScript stahovat a analyzovat za běhu, zatímco WASM kód je připraven ke spuštění díky svému předkompilovanému kódu.
- WebAssembly je jazyk nízké úrovně. Oproti tomu JavaScript je jazyk na vysoké úrovni. Díky vysoké úrovni je práce s JS snadnější. WASM na nízké úrovni se ale může spouštět mnohem rychleji než JavaScript.
- V neposlední řadě má JavaScript velkou a aktivní komunitu. Pokud tedy hledáte lepší vývojářský zážitek, je JS jasnou volbou. WebAssembly je na druhou stranu relativně nový, a proto postrádá dostatečné zdroje.
Jako vývojář se s výběrem nemusíte příliš trápit. Je to proto, že jak JS, tak WASM pracují společně, a ne proti sobě.
Pokud tedy vytváříte vysoce výkonnou aplikaci, můžete použít WebAssembly pro ty části kódu, které vyžadují maximální výkon. JavaScript API vám umožní načíst a používat moduly WASM přímo ve vašem JavaScriptovém kódu.
Závěrečné myšlenky
Celkově je WebAssembly skvělým doplňkem k JavaScriptu. Podněcuje vývojáře k vytváření výkonných aplikací na webu i mimo něj. A to vše bez snahy o nahrazení JavaScriptu.
Může se ale WASM vyvinout v kompletní balíček a nahradit JavaScript? S ohledem na cíle WebAssembly se to pravděpodobně nestane. Nicméně, myšlenka nahrazení JavaScriptu WebAssembly v budoucnu není zcela vyloučena.
Dále si prohlédněte nejlepší JavaScript (JS) knihovny pro uživatelské rozhraní, určené pro vývoj moderních aplikací.