Dukungan untuk
teknologi WebAssembly (Wasm) telah muncul di browser relatif baru-baru ini. Tetapi teknologi ini juga dapat memperluas kemampuan web, menjadikannya sebuah platform yang mampu mendukung aplikasi seperti itu yang biasanya dianggap sebagai desktop.
Menguasai WebAssembly bisa menjadi tugas yang menakutkan bagi pengembang web. Namun, kompiler
AssemblyScript dapat memperbaiki situasi.
Penulis artikel, yang kami terbitkan hari ini, menawarkan pertama untuk berbicara tentang mengapa WebAssembly adalah teknologi yang sangat menjanjikan, dan kemudian untuk melihat bagaimana AssemblyScript dapat membantu membuka potensi Wasm.
Perakitan web
WebAssembly dapat disebut bahasa tingkat rendah untuk browser. Ini memberi pengembang kemampuan untuk membuat kode yang mengkompilasi menjadi sesuatu selain JavaScript. Ini memungkinkan program yang dimasukkan dalam halaman web berfungsi hampir secepat aplikasi asli untuk berbagai platform. Program semacam itu dijalankan dalam lingkungan yang terbatas dan aman.
Perwakilan tim yang bertanggung jawab untuk pengembangan semua browser terkemuka (Chrome, Firefox, Safari dan Edge) terlibat dalam pembuatan standar WebAssembly. Mereka menyetujui
arsitektur sistem pada awal 2017. Sekarang semua browser di atas mendukung WebAssembly. Bahkan, teknologi ini dapat digunakan di
sekitar 87% browser.
Kode WebAssembly ada dalam format biner. Ini berarti bahwa kode tersebut lebih kecil dari kode JavaScript yang sama dan memuat lebih cepat. Kode Wasm, selain itu, dapat disajikan dalam
format teks , sehingga orang dapat membaca dan mengeditnya.
Ketika standar WebAssembly pertama kali muncul, beberapa pengembang berpikir bahwa itu bisa menggantikan JavaScript dan menjadi bahasa utama web. Tapi WebAssembly paling baik dilihat sebagai alat baru yang terintegrasi dengan baik dengan platform web yang ada. Ini adalah salah satu
tujuan prioritasnya .
Alih-alih mengganti JavaScript di mana bahasa ini telah digunakan untuk waktu yang lama dan berhasil, WebAssembly memberikan peluang menarik baru bagi pengembang web. Benar, kode Wasm tidak memiliki akses langsung ke DOM, sehingga sebagian besar proyek web yang ada akan terus menggunakan JavaScript. Bahasa ini, selama bertahun-tahun pengembangan dan optimalisasi, sudah cukup cepat. Dan WebAssembly memiliki
aplikasi sendiri:
- Game
- Perhitungan ilmiah, visualisasi, simulasi.
- Aplikasi CAD.
- Mengedit gambar dan video.
Semua penggunaan ini untuk Wasm dipersatukan oleh apa yang masing-masing aplikasi mereka biasanya dianggap sebagai desktop. Tetapi karena kenyataan bahwa WebAssembly memungkinkan Anda untuk mencapai tingkat kinerja yang mendekati asli, banyak aplikasi serupa sekarang dapat diimplementasikan menggunakan platform web.
WebAssembly dapat memanfaatkan proyek web yang ada. Contohnya adalah proyek
Figma . Berkat penggunaan Wasm, waktu pemuatan proyek ini meningkat secara signifikan. Jika situs web menggunakan kode yang melakukan perhitungan berat, maka, untuk meningkatkan kinerja situs web ini, masuk akal untuk mengganti hanya kode tersebut dengan analog WebAssembly.
Anda mungkin ingin mencoba menggunakan WebAssembly di proyek Anda sendiri. Bahasa ini dapat dipelajari dan ditulis
langsung di situ . Namun, bagaimanapun, WebAssembly awalnya dikembangkan sebagai
target kompilasi untuk bahasa lain. Itu
dirancang dengan dukungan yang baik untuk C dan C ++. Dukungan
eksperimental Wasm muncul di Go 1.11. Banyak upaya yang dilakukan untuk menulis aplikasi Wasm di
Rust .
Tetapi sangat mungkin bahwa pengembang web tidak ingin mempelajari C, C ++, Go, atau Rust hanya untuk menggunakan WebAssembly. Apa yang mereka lakukan Jawaban untuk pertanyaan ini dapat memberikan AssemblyScript.
AssemblyScript
AssemblyScript adalah kompiler yang mengubah kode TypeScript ke kode WebAssembly. TypeScript adalah bahasa yang dikembangkan oleh Microsoft. Ini adalah superset dari JavaScript, menampilkan dukungan tipe yang ditingkatkan dan beberapa fitur lainnya. TypeScript telah menjadi bahasa yang cukup
populer . Perlu dicatat bahwa AssemblyScript mampu mengkonversi ke Wasm hanya set konstruksi TypeScript yang terbatas. Ini berarti bahwa bahkan seseorang yang tidak terbiasa dengan TypeScript dapat dengan cepat mempelajari bahasa ini pada tingkat yang cukup untuk menulis kode yang dipahami oleh AssemblyScript.
Selain itu, mengingat fakta bahwa TypeScript sangat mirip dengan JavaScript, kita dapat mengatakan bahwa teknologi AssemblyScript memungkinkan pengembang web untuk dengan mudah mengintegrasikan modul Wasm ke dalam proyek mereka tanpa perlu mempelajari bahasa yang sama sekali baru.
Contoh
Mari kita menulis modul AssemblyScript pertama kami. Semua kode yang akan kita diskusikan sekarang dapat ditemukan di
GitHub . Untuk
mendukung WebAssembly, kita memerlukan setidaknya
Node.js 8.
Buat direktori baru, inisialisasi proyek npm dan instal AssemblyScript:
mkdir assemblyscript-demo cd assemblyscript-demo npm init npm install --save-dev github:AssemblyScript/assemblyscript
Perhatikan bahwa AssemblyScript harus diinstal langsung dari
repositori GitHub proyek. AssemblyScript belum diterbitkan dalam npm, karena pengembang
belum menganggapnya siap untuk digunakan secara luas.
Kami akan membuat file tambahan menggunakan perintah
asinit
termasuk dalam AssemblyScript:
npx asinit .
Sekarang bagian
scripts
package.json
kami harus mengambil bentuk berikut:
{ "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" } }
File
index.js
terletak di folder root proyek akan terlihat seperti ini:
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 });
Ini memungkinkan Anda untuk memasukkan modul WebAssembly dalam kode Anda menggunakan perintah need. Yaitu - dengan cara yang sama seperti modul JavaScript biasa terhubung.
Folder
assembly
berisi file
index.ts
. Ini memiliki kode sumber yang ditulis sesuai dengan aturan AssemblyScript. Kode boilerplate yang dihasilkan secara otomatis adalah fungsi sederhana untuk menambahkan dua angka:
export function add(a: i32, b: i32): i32 { return a + b; }
Mungkin Anda mengharapkan tanda tangan dari fungsi yang mirip terlihat seperti
add(a: number, b: number): number
. Jadi akan terlihat jika ditulis dalam TypeScript biasa. Namun di sini, alih-alih tipe
number
, tipe
i32
. Ini terjadi karena kode AssemblyScript menggunakan
tipe WebAssembly spesifik untuk bilangan bulat dan angka floating point, daripada tipe
angka generik dari TypeScript.
Mari kita kumpulkan proyek:
npm run asbuild
File-file berikut ini akan muncul di folder
build
:
optimized.wasm optimized.wasm.map optimized.wat untouched.wasm untouched.wasm.map untouched.wat
Ada versi perakitan yang dioptimalkan dan teratur. Setiap versi majelis memberi kita file biner .wasm,
peta peta .wasm.map, dan representasi tekstual dari kode biner dalam file .wat. Presentasi pengujian kode Wasm dimaksudkan untuk programmer, tetapi kami bahkan tidak akan melihat file ini. Sebenarnya, salah satu alasan untuk menggunakan AssemblyScript adalah karena menghilangkan kebutuhan untuk bekerja dengan kode Wasm.
Sekarang mari kita jalankan Node.js dalam mode REPL dan pastikan bahwa modul Wasm yang dikompilasi dapat digunakan dengan cara yang sama seperti modul JS biasa:
$ node Welcome to Node.js v12.10.0. Type ".help" for more information. > const add = require('./index').add; undefined > add(3, 5) 8
Secara umum, ini semua yang diperlukan untuk menggunakan teknologi WebAssembly di Node.js.
Melengkapi proyek dengan naskah pengamat
Untuk membangun kembali modul secara otomatis selama pengembangan ketika membuat perubahan, saya sarankan menggunakan paket
onchange . Faktanya adalah bahwa AssemblyScript
belum memiliki sistem sendiri untuk memonitor perubahan file. Instal paket onchange:
npm install --save-dev onchange
Tambahkan
asbuild:watch
script ke
package.json
.
Bendera -i
disertakan dalam perintah sehingga proses pembangunan dimulai satu kali ketika skrip dipanggil, sebelum semua peristiwa terjadi.
{ "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" } }
Sekarang, alih-alih terus menjalankan perintah
asbuild
, jalankan saja
asbuild:watch
sekali.
Performa
Kami akan menulis tes sederhana yang akan mengevaluasi tingkat kinerja kode Wasm. Ruang lingkup utama WebAssembly adalah untuk menyelesaikan tugas-tugas yang menggunakan prosesor secara intensif. Sebagai contoh, ini adalah semacam perhitungan "berat". Mari kita membuat fungsi yang mencari tahu apakah angka tertentu adalah prima.
Implementasi JS dasar dari fungsi serupa ditunjukkan di bawah ini. Ini diatur dengan sangat sederhana, memeriksa angka dengan kekerasan, tetapi untuk tujuan kami ini cocok, karena melakukan perhitungan dalam jumlah besar.
function isPrime(x) { if (x < 2) { return false; } for (let i = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; }
Fungsi serupa, ditulis untuk kompiler AssemblyScript, terlihat hampir sama. Perbedaan utama adalah adanya anotasi jenis dalam kode:
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; }
Untuk menganalisis kinerja kode, kami akan menggunakan paket
Benchmark.js . Pasang itu:
npm install --save-dev benchmark
Buat file
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();
Inilah yang saya berhasil dapatkan setelah menjalankan perintah
node benchmark
di komputer saya:
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.
Seperti yang Anda lihat, implementasi AssemblyScript dari algoritma itu 20% lebih cepat daripada implementasi JS. Namun, perhatikan bahwa tes ini adalah
microbenchmark . Jangan terlalu mengandalkan hasilnya.
Untuk menemukan hasil yang lebih dapat diandalkan dari penelitian kinerja proyek-proyek AssemblyScript - Saya sarankan melihat
ini dan tolok ukur
ini .
Menggunakan Modul Wasm di Halaman Web
Mari kita gunakan modul Wasm kami di halaman web. Kami mulai dengan membuat file
index.html
dengan konten berikut:
<!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>
Sekarang buat file
demo.js
yang kodenya ditunjukkan di bawah ini. Ada
banyak cara untuk memuat modul WebAssembly. Yang paling efisien adalah mengkompilasi dan menginisialisasi mereka dalam mode streaming menggunakan fungsi
WebAssembly.instantiateStreaming . Harap perhatikan bahwa kami perlu mendefinisikan kembali fungsi
batal , yang dipanggil jika beberapa
pernyataan tidak dieksekusi.
(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.`; }); })();
Selanjutnya, instal paket
server statis . Kita memerlukan server karena fakta bahwa untuk menggunakan fungsi
WebAssembly.instantiateStreaming
, modul harus diservis menggunakan
application/wasm
MIME
application/wasm
.
npm install --save-dev static-server
Tambahkan skrip yang sesuai ke
package.json
:
{ "scripts": { "serve-demo": "static-server" } }
Sekarang
npm run serve-demo
dan buka URL host lokal di browser. Jika Anda memasukkan nomor tertentu dalam formulir, Anda dapat mengetahui apakah itu sederhana atau tidak. Sekarang, dalam mengembangkan AssemblyScript, kita telah jauh dari menulis kode untuk menggunakannya di Node.js dan di halaman web.
Ringkasan
WebAssembly, dan karenanya AssemblyScript, tidak dapat entah bagaimana mempercepat situs apa pun secara ajaib. Tapi Wasm tidak pernah ditugaskan untuk mempercepat segalanya. Teknologi ini luar biasa karena membuka jalan ke web untuk aplikasi jenis baru.
Hal serupa dapat dikatakan tentang AssemblyScript. Teknologi ini menyederhanakan akses ke WebAssembly untuk sejumlah besar pengembang. Hal ini memungkinkan, ketika membuat kode dalam bahasa yang dekat dengan JavaScript, untuk menggunakan kemampuan WebAssembly untuk memecahkan masalah komputasi yang kompleks.
Pembaca yang budiman! Bagaimana Anda menilai prospek untuk menggunakan AssemblyScript di proyek Anda?
