У четвртом делу наше серије о WebAssembly-ју (WASM) за почетнике, детаљно ћемо размотрити интеракцију између WebAssembly-ја и JavaScript-a.
Овде ћете научити како да употребите WebAssembly унутар вашег JavaScript кода. Такође, истражићемо и API-je које JavaScript нуди за рад са WebAssembly-jem.
WebAssembly је отворени стандард за бинарни формат који програмерима омогућава да покрећу апликације са брзином блиском изворном коду, директно у веб прегледачима. Уколико нисте упознати са овом технологијом, препоручујемо да погледате претходне делове нашег водича.
Кренимо!
Коришћење WebAssembly-ја са JavaScript-ом
У првом делу нашег увода у WebAssembly, објаснили смо како WASM ради. Да бисте креирали ефикасан код за вашу веб апликацију, неопходно је да користите WASM API-је и функције које су доступне у JavaScript-у. Такође смо споменули како JavaScript framework-ovi могу користити WASM за изградњу апликација са високим перформансама.
Међутим, тренутно није могуће директно учитати WASM модуле користећи <script type=”module”>, као што то радимо са ES6 модулима. Ту JavaScript ступа на сцену. Он омогућава учитавање и компајлирање WASM кода у веб прегледачу. Процес се одвија кроз следеће кораке:
- Учитајте .wasm бајтове у ArrayBuffer или у типизирани низ.
- Користите `WebAssembly.Module` за компајлирање бајтова.
- Затим, инстанцирајте `WebAssembly.Module` са увозима да бисте добили извозе које можете користити.
Дакле, потребно је да имате унапред компајлиран WASM модул. Имате више опција за то. Можете користити Rust, C/C++, AssemblyScript, па чак и TinyGo (Go) да напишете код и касније га трансформишете у .wasm модул.
Технички гледано, WebAssembly је циљ компилације за различите програмске језике. То значи да прво морате написати код у изабраном језику, а затим користити генерисани бинарни код у вашој апликацији (веб или не-веб). Такође, уколико планирате да користите WASM на серверима, мораћете да користите WASI за интеракцију са оперативним системом.
Пошто WebAssembly користи линеарну меморију преко проширивог низа, и JavaScript и WASM могу синхроно да јој приступе, омогућавајући вам да креирате брзе апликације са много функција.
Примери употребе WebAssembly-ја и JavaScript-а
Погледајмо примере како можете користити WASM са JavaScript-ом.
Као што смо претходно споменули, потребан вам је унапред компајлиран WASM модул. У овом примеру ћемо користити Emscripten (C/C++). Пошто WASM нуди бинарни формат са високим перформансама, можемо покренути генерисани код заједно са JavaScript-ом или другим програмским језицима.
Подешавање окружења
Пошто користимо Emscripten, потребно је да инсталирамо emsdk алат. Он ће вам омогућити да преведете ваш C/C++ код у .wasm код.
Једноставно покрените следећу команду у вашем терминалу. Ако немате инсталиран Git, погледајте наш водич „Open Source 101: Систем контроле верзија и 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$
У фасцикли `emsdk`, покрећемо још једну команду да бисмо преузели најновију верзију Emscripten-a.
Потребно је да покренете следеће команде.
./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
Последња команда, `source ./emsdk_env.sh`, осигурава да је путања `emcc`, компајлера Emscripten алата, исправно подешена и да је можете користити за компилацију кода.
#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$
Сада можемо да генеришемо WASM код помоћу следеће команде.
emcc hello-techblog.co.rs.c -o hello-techblog.co.rs.js
#Output [email protected]:~/Projects/WASM2$ emcc hello-techblog.co.rs.c -o hello-techblog.co.rs.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-techblog.co.rs.c hello-techblog.co.rs.js hello-techblog.co.rs.wasm [email protected]:~/Projects/WASM2$
Као што видите, добијате излазне фајлове `hello-techblog.co.rs.js` и `hello-techblog.co.rs.wasm`. Можете проверити фајлове у вашем пројектном директоријуму користећи команду `dir`.
Оба ова фајла су неопходна. `hello-techblog.co.rs.wasm` садржи компајлирани WASM код. `hello-techblog.co.rs.js` фајл, с друге стране, садржи JavaScript код који је потребан за покретање WASM модула. Пошто Emscripten подржава покретање у веб прегледачу и Node.js окружењу, можемо га тестирати помоћу Node-a.
node hello-techblog.co.rs.js
#Output [email protected]:~/Projects/WASM2$ node hello-techblog.co.rs.js Hello, techblog.co.rs! [email protected]:~/Projects/WASM2$
Ако желите да видите како ради у веб прегледачу, можете генерисати HTML фајл помоћу Emscripten-a. Покрените следећу команду.
emcc hello-techblog.co.rs.c -o hello-techblog.co.rs.html
#Output [email protected]:~/Projects/WASM2$ emcc hello-techblog.co.rs.c -o hello-techblog.co.rs.html [email protected]:~/Projects/WASM2$
Да бисте покренули HTML фајл, можете користити Python 3 HTTP сервер покретањем следеће команде.
python3 -m http.server 8000
Сада идите на http://localhost:8000/hello-techblog.co.rs.html да видите резултат.
Напомена: Већина система има унапред инсталиран Python. Ако га немате, можете га лако инсталирати пре него што покренете Python3 сервер.
Коришћење JavaScript API-ја за рад са WASM-ом
У овом делу ћемо детаљније размотрити JavaScript WASM API. Научићемо како да учитамо WASM код и да га извршимо. Прво, погледајмо следећи код.
fetch('hello-techblog.co.rs.wasm').then( response => response.arrayBuffer()) .then (bytes => WebAssembly.instantiate(bytes)) .then(result=> alert(result.instance.exports.answer()))
Горе наведени код користи следеће JavaScript API-је:
- `fetch()` API прегледача
- `WebAssembly.instantiate`
Поред њих, постоје и други API-ји који су вредни пажње, укључујући:
- `WebAssembly.compile`
- `WebAssembly.Instance`
- `WebAssembly.instantiate`
- `WebAssembly.instantiateStreaming`
`fetch()` API прегледача
`fetch()` API учитава `.wasm` мрежни ресурс. Уколико покушавате да га учитате локално, мораћете да онемогућите дељење ресурса између различитих домена (CORS) да бисте успешно учитали мрежни ресурс. Алтернативно, можете користити Node.js сервер да учита ресурс уместо вас. Да бисте инсталирали и покренули Node.js сервер, покрените следећу команду:
sudo apt install npm
Затим, покрените следећу команду да покренете сервер:
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"
Отвориће се веб прегледач у којем можете видети све ваше пројектне фајлове.
Сада отворите `hello-techblog.co.rs.html` и покрените веб девелоперске алате. Отворите конзолу и откуцајте следеће:
fetch(„hello-techblog.co.rs.wasm“);
Вратиће следеће обећање:
#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-techblog.co.rs.wasm" [[Prototype]]: Response
Такође можете написати следећи скрипт и покренути га кроз HTML:
Да бисте покренули ваше WASM модуле на серверу, потребно је да користите следећи код у Node.js окружењу:
const fs = require('fs'); const run = async() => { const buffer = fs.readFileSync("./hello-techblog.co.rs.wasm"); const result = await WebAssembly.instantiate(buffer); console.log(result.instance.exports.answer()); }; run();
Препоручујемо да прочитате документацију WebAssembly JavaScript API-ја да бисте сазнали више.
JavaScript vs. WASM
Да бисмо разумели повезаност WASM-а и JavaScript-а, потребно је да их упоредимо. У суштини, WASM је бржи и користи бинарни формат који је погодан за циљну компилацију, док је JavaScript програмски језик високог нивоа. WASM-ов бинарни код га чини тежим за учење, али постоје начини за ефикасан рад са WASM-ом.
Кључне разлике између WASM-а и JavaScript-а:
- WASM је компилирани језик, док је JS интерпретирани језик. Прегледач мора да преузме и рашчлани JavaScript у току извршавања, док је WASM код спреман за извршавање са својим унапред компајлираним кодом.
- WebAssembly је језик ниског нивоа. За разлику од тога, JavaScript је језик високог нивоа. Пошто је на високом нивоу, JS је лакши за рад. Међутим, WASM на ниском нивоу се извршава много брже од JavaScript-a.
- JavaScript има велику заједницу. Ако тражите боље искуство у развоју, JS је очигледан избор. WebAssembly је релативно нов и зато нема толико ресурса.
Као програмер, не морате да бринете о избору само једног од њих. JS и WASM функционишу заједно, а не као конкуренти.
Дакле, ако правите апликацију која захтева високе перформансе, можете користити WebAssembly да кодирате само делове који захтевају перформансе. JavaScript API вам може помоћи да преузмете и користите WASM модуле директно у вашем JavaScript коду.
Завршне мисли
WebAssembly је одличан додатак JavaScript-у. Он омогућава програмерима да креирају апликације високих перформанси, како у веб прегледачима, тако и ван њих. При томе, WASM не покушава да замени JavaScript.
Међутим, да ли ће WASM еволуирати у потпун пакет и заменити JavaScript? Вероватно не, с обзиром на циљеве WebAssembly-ја. Ипак, није искључена могућност да WebAssembly замени JavaScript у будућности.
Затим, погледајте најбоље JavaScript (JS) UI библиотеке за израду модерних апликација.