Uygulamanızın JavaScript'indeki aktif yolu WebAssembly ile değiştirme

Sürekli olarak hızlı

Önceki makalelerimde, WebAssembly'nin C/C++ kitaplık ekosistemini web'e nasıl getirdiğinizden bahsetmiştim. C/C++ kitaplıklarını yoğun şekilde kullanan uygulamalardan biri, C++'dan WebAssembly'e derlenmiş çeşitli codec'lerle resimleri sıkıştırmanıza olanak tanıyan web uygulamamız squoosh'tur.

WebAssembly, .wasm dosyalarında depolanan bayt kodunu çalıştıran düşük düzey bir sanal makinedir. Bu bayt kodu, güçlü bir şekilde yazılmış ve ana sistem için JavaScript'den çok daha hızlı derlenip optimize edilebilecek şekilde yapılandırılmıştır. WebAssembly, en başından itibaren korumalı alan ve yerleştirme düşünülerek yazılmış kodları çalıştırmak için bir ortam sağlar.

Deneyimlerime göre, web'deki performans sorunlarının çoğu zorunlu düzen ve aşırı boyamadan kaynaklanıyor ancak uygulamaların zaman zaman çok zaman alan, hesaplama açısından pahalı bir görev yapması gerekiyor. WebAssembly bu konuda yardımcı olabilir.

The Hot Path

Squoosh'ta, bir resim arabelleğini 90 derecenin katları kadar döndüren bir JavaScript işlevi yazdık. OffscreenCanvas bu amaç için ideal olsa da hedeflediğimiz tarayıcılarda desteklenmemektedir ve Chrome'da biraz hatalı.

Bu işlev, bir giriş resminin her pikseli üzerinde iterasyon gerçekleştirir ve döndürme işlemini gerçekleştirmek için pikseli çıkış resminde farklı bir konuma kopyalar. 4094 piksel x 4096 piksel (16 megapiksel) boyutunda bir resim için "sıcak yol" olarak adlandırdığımız iç kod bloğunun 16 milyondan fazla iterasyonuna ihtiyaç duyulur. Oldukça fazla sayıda iterasyona rağmen, test ettiğimiz üç tarayıcıdan ikisi görevi 2 saniye veya daha kısa sürede tamamladı. Bu tür etkileşimler için kabul edilebilir bir süre.

for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
    for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
    const in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
    outBuffer[i] = inBuffer[in_idx];
    i += 1;
    }
}

Ancak bir tarayıcı 8 saniyeden uzun sürüyor. Tarayıcıların JavaScript'i optimize etme şekli çok karmaşıktır ve farklı motorlar farklı şeyler için optimizasyon yapar. Bazıları ham yürütme için, bazıları DOM ile etkileşim için optimize edilir. Bu durumda, bir tarayıcıda optimize edilmemiş bir yola ulaştık.

Öte yandan WebAssembly tamamen ham yürütme hızı üzerine kuruludur. Bu nedenle, bu tür kodlar için tarayıcılar arasında hızlı ve tahmin edilebilir performans elde etmek istiyorsanız WebAssembly'den yararlanabilirsiniz.

Öngörülebilir performans için WebAssembly

Genel olarak JavaScript ve WebAssembly aynı en yüksek performansı sağlayabilir. Ancak JavaScript için bu performansa yalnızca "hızlı yoldan" ulaşılabilir ve bu "hızlı yolda" kalmak genellikle zordur. WebAssembly'in sunduğu önemli avantajlardan biri, tarayıcılar arasında bile öngörülebilen performanstır. Katı yazım ve düşük düzey mimari, derleyicinin daha güçlü garantiler vermesine olanak tanır. Böylece WebAssembly kodunun yalnızca bir kez optimize edilmesi gerekir ve her zaman "hızlı yolu" kullanır.

WebAssembly için yazma

Daha önce, C/C++ kitaplıklarını alıp işlevlerini web'de kullanmak için WebAssembly'e derliyorduk. Kitaplıkların koduna pek dokunmadık. Tarayıcı ile kitaplık arasında köprü oluşturmak için yalnızca az miktarda C/C++ kodu yazdık. Bu seferki motivasyonumuz farklı: WebAssembly'in avantajlarından yararlanabilmek için sıfırdan WebAssembly'i göz önünde bulundurarak bir şey yazmak istiyoruz.

WebAssembly mimarisi

WebAssembly için kod yazarken WebAssembly'in aslında ne olduğu hakkında biraz daha bilgi sahibi olmanız faydalı olacaktır.

WebAssembly.org'dan alıntı yaparak:

Bir C veya Rust kodu parçasını WebAssembly olarak derlediğinizde modül beyanı içeren bir .wasm dosya elde edersiniz. Bu beyan, modülün ortamından beklediği "içe aktarma"ların listesinden, bu modülün ana makineye sunduğu dışa aktarma işlemlerinin (işlevler, sabitler, bellek parçaları) listesinden ve elbette içindeki işlevlere ait gerçek ikili talimatlardan oluşur.

Bu konuyu inceleyene kadar fark etmediğim bir şey: WebAssembly'i "stack tabanlı sanal makine" yapan yığın, WebAssembly modüllerinin kullandığı bellek parçasında depolanmaz. Paket tamamen sanal makine içindedir ve web geliştiricileri tarafından erişilemez (Geliştirici Araçları hariç). Bu nedenle, hiç ek belleğe ihtiyaç duymayan ve yalnızca sanal makine içi yığını kullanan WebAssembly modülleri yazılabilir.

Bizim durumumuzda, resmimizin piksellerine keyfi erişim izni vermek ve bu resmin döndürülmüş bir sürümünü oluşturmak için biraz ek bellek kullanmamız gerekir. WebAssembly.Memory bunun içindir.

Bellek yönetimi

Genellikle, ek bellek kullandıktan sonra bu belleği bir şekilde yönetmeniz gerekir. Belleğin hangi bölümleri kullanılıyor? Hangileri ücretsiz? Örneğin, C'de n art arda baytlık bir bellek alanı bulan malloc(n) işlevi vardır. Bu tür işlevlere "dağıtıcılar" da denir. Elbette, kullanılan ayırıcının uygulanması WebAssembly modülünüze dahil edilmelidir ve dosya boyutunuzu artırır. Bu bellek yönetimi işlevlerinin boyutu ve performansı, kullanılan algoritmaya bağlı olarak oldukça önemli ölçüde değişiklik gösterebilir. Bu nedenle birçok dil, aralarından seçim yapabileceğiniz birden fazla uygulama sunar ("dmalloc", "emmalloc", "wee_alloc" vb.).

Bizim durumumuzda, WebAssembly modülünü çalıştırmadan önce giriş resminin boyutlarını (ve dolayısıyla çıkış resminin boyutlarını) biliyoruz. Burada bir fırsat gördük: Geleneksel olarak, giriş resminin RGBA arabelleğini bir WebAssembly işlevine parametre olarak iletir ve döndürülmüş resmi bir dönüş değeri olarak döndürürdük. Bu döndürülen değeri oluşturmak için ayırıcıyı kullanmamız gerekir. Ancak gereken toplam bellek miktarını (giriş resminin iki katı, giriş için bir kez ve çıkış için bir kez) bildiğimizden, giriş resmini JavaScript kullanarak WebAssembly belleğine koyabilir, 2. döndürülmüş resmi oluşturmak için WebAssembly modülünü çalıştırabilir ve ardından sonucu geri okumak için JavaScript'i kullanabiliriz. Bellek yönetimi kullanmadan da bu işlemi yapabiliriz.

Seçenek çok

WebAssembly'ye dönüştürmek istediğimiz orijinal JavaScript işlevine bakarsanız bunun JavaScript'e özgü API'ler içermeyen, tamamen hesaplamalı bir kod olduğunu görebilirsiniz. Bu nedenle, bu kodu herhangi bir dile taşımak oldukça kolaydır. WebAssembly'e derlenen 3 farklı dili değerlendirdik: C/C++, Rust ve AssemblyScript. Her bir dil için yanıtlamamız gereken tek soru şudur: Bellek yönetimi işlevlerini kullanmadan ham belleğe nasıl erişebiliriz?

C ve Emscripten

Emscripten, WebAssembly hedefi için bir C derleyicisidir. Emscripten'in amacı, GCC veya clang gibi tanınmış C derleyicilerinin yerini almaktır ve çoğunlukla işaret uyumludur. Mevcut C ve C++ kodunun WebAssembly'e derlenmesini mümkün olduğunca kolaylaştırmak isteyen Emscripten, bu özelliği misyonunun temel bir parçası olarak görmektedir.

Ham belleğe erişmek C'nin doğasında vardır ve işaretçiler de bu nedenle mevcuttur:

uint8_t* ptr = (uint8_t*)0x124;
ptr[0] = 0xFF;

Burada 0x124 sayısını, işaretsiz 8 bitlik tamsayılara (veya baytlara) işaret eden bir işaretçiye dönüştürüyoruz. Bu işlem, ptr değişkenini 0x124 bellek adresinden başlayan ve diğer tüm diziler gibi kullanabileceğimiz bir diziye dönüştürür. Böylece, okuma ve yazma için tek tek baytlara erişebiliriz. Bizim durumumuzda, döndürmeyi gerçekleştirmek için yeniden sıralamak istediğimiz bir resmin RGBA arabelleğine bakıyoruz. Bir pikseli taşımak için aslında aynı anda 4 art arda bayt taşımamız gerekir (her kanal için bir bayt: K, G, B ve A). Bu işlemi kolaylaştırmak için imzalanmamış, 32 bitlik tam sayı dizisi oluşturabiliriz. Kural olarak, giriş resmimiz 4. adreste başlar ve çıkış resmimiz doğrudan giriş resminin bitiminden sonra başlar:

int bpp = 4;
int imageSize = inputWidth * inputHeight * bpp;
uint32_t* inBuffer = (uint32_t*) 4;
uint32_t* outBuffer = (uint32_t*) (inBuffer + imageSize);

for (int d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
    for (int d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
    int in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
    outBuffer[i] = inBuffer[in_idx];
    i += 1;
    }
}

JavaScript işlevinin tamamını C'ye taşıdıktan sonra emcc ile C dosyasını derleyebiliriz:

$ emcc -O3 -s ALLOW_MEMORY_GROWTH=1 -o c.js rotate.c

Her zaman olduğu gibi emscripten, c.js adlı bir yapıştırma kodu dosyası ve c.wasm adlı bir wasm modülü oluşturur. wasm modülünün yalnızca yaklaşık 260 bayta sıkıştırıldığını, yapıştırma kodunun ise sıkıştırıldıktan sonra yaklaşık 3,5 KB olduğunu unutmayın. Biraz uğraştıktan sonra, yapıştırıcı kodunu kaldırıp WebAssembly modüllerini standart API'lerle örnekleyebildik. C standart kitaplığından hiçbir şey kullanmadığınız sürece bu, Emscripten ile genellikle mümkündür.

Rust

Rust, zengin bir tür sistemine, çalışma zamanına sahip olmayan ve bellek güvenliği ile iş parçacığı güvenliğini garanti eden bir sahiplik modeline sahip yeni ve modern bir programlama dilidir. Rust, temel bir özellik olarak WebAssembly'i de destekler. Rust ekibi, WebAssembly ekosistemine birçok mükemmel araç katkısında bulunmuştur.

Bu araçlardan biri, rustwasm çalışma grubunun wasm-pack aracıdır. wasm-pack, kodunuzu alıp webpack gibi paketleyicilerle hazır olarak çalışan web dostu bir modüle dönüştürür. wasm-pack son derece kullanışlı bir deneyimdir ancak şu anda yalnızca Rust için kullanılabilir. Grup, WebAssembly'i hedefleyen diğer diller için destek eklemeyi düşünüyor.

Rust'ta dilim, C'deki dizilere benzer. C'de olduğu gibi, başlangıç adreslerimizi kullanan dilim oluşturmamız gerekir. Bu, Rust'un zorunlu kıldığı bellek güvenliği modeline aykırıdır. Bu nedenle, istediğimiz sonucu elde etmek için unsafe anahtar kelimesini kullanmamız gerekir. Bu anahtar, söz konusu modele uymayan kod yazmamıza olanak tanır.

let imageSize = (inputWidth * inputHeight) as usize;
let inBuffer: &mut [u32];
let outBuffer: &mut [u32];
unsafe {
    inBuffer = slice::from_raw_parts_mut::<u32>(4 as *mut u32, imageSize);
    outBuffer = slice::from_raw_parts_mut::<u32>((imageSize * 4 + 4) as *mut u32, imageSize);
}

for d2 in 0..d2Limit {
    for d1 in 0..d1Limit {
    let in_idx = (d1Start + d1 * d1Advance) * d1Multiplier + (d2Start + d2 * d2Advance) * d2Multiplier;
    outBuffer[i as usize] = inBuffer[in_idx as usize];
    i += 1;
    }
}

Rust dosyalarını şunu kullanarak derleme:

$ wasm-pack build

yaklaşık 100 baytlık bir yapıştırma kodu içeren 7,6 KB'lık bir wasm modülü oluşturur (her ikisi de gzip'den sonra).

AssemblyScript

AssemblyScript, TypeScript'ten WebAssembly'e derleyici olmayı amaçlayan oldukça genç bir projedir. Ancak, herhangi bir TypeScript'i tüketmeyeceğini unutmayın. AssemblyScript, TypeScript ile aynı söz dizimini kullanır ancak standart kitaplığı kendi kitaplığıyla değiştirir. Standart kitaplıkları, WebAssembly'nin özelliklerini modeller. Bu, elinizdeki TypeScript'i WebAssembly olarak derleyemeyeceğiniz anlamına gelir ancak WebAssembly yazmak için yeni bir programlama dili öğrenmeniz gerekmediği anlamına gelmez.

    for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
      for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
        let in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
        store<u32>(offset + i * 4 + 4, load<u32>(in_idx * 4 + 4));
        i += 1;
      }
    }

rotate() işlevimizin küçük tür yüzeyi göz önüne alındığında, bu kodu AssemblyScript'e taşımak oldukça kolaydı. load<T>(ptr: usize) ve store<T>(ptr: usize, value: T) işlevleri, ham belleğe erişmek için AssemblyScript tarafından sağlanır. AssemblyScript dosyamızı derlemek için AssemblyScript/assemblyscript npm paketini yüklememiz ve

$ asc rotate.ts -b assemblyscript.wasm --validate -O3

AssemblyScript bize yaklaşık 300 baytlık bir wasm modülü ve hiçbir yapıştırıcı kod sağlar. Modül yalnızca standart WebAssembly API'leriyle çalışır.

WebAssembly Adli İncelemesi

Rust'ın 7,6 KB'lık boyutu, diğer 2 dile kıyasla şaşırtıcı derecede büyük. WebAssembly ekosisteminde, WebAssembly dosyalarınızı (oluşturuldukları dilden bağımsız olarak) analiz etmenize, neler olduğunu anlamanıza ve durumunuzu iyileştirmenize yardımcı olabilecek birkaç araç vardır.

Twiggy

Twiggy, Rust'un WebAssembly ekibi tarafından geliştirilen ve WebAssembly modülünden bir dizi yararlı veri çıkaran bir araçtır. Rust'a özgü olmayan bu araç, modülün çağrı grafiği gibi öğeleri incelemenize, kullanılmayan veya gereksiz bölümleri belirlemenize ve modülünüzün toplam dosya boyutuna hangi bölümlerin katkıda bulunduğunu anlamanıza olanak tanır. İkincisi, Twiggy'nin top komutuyla yapılabilir:

$ twiggy top rotate_bg.wasm
Twiggy kurulum ekran görüntüsü

Bu durumda, dosya boyutumuzun büyük kısmının ayırıcıdan kaynaklandığını görebiliriz. Kodumuz dinamik atama kullanmadığı için bu durum şaşırtıcıydı. "İşlev adları" alt bölümü de bu duruma katkıda bulunan önemli faktörlerden biridir.

wasm-strip

wasm-strip, WebAssembly Binary Toolkit (WebAssembly İkili Aracı Kiti) veya kısaca wabt'den bir araçtır. WebAssembly modüllerini incelemenize ve değiştirmenize olanak tanıyan birkaç araç içerir. wasm2wat, bir ikilik wasm modülünü insanlar tarafından okunabilir bir biçime dönüştüren bir disassembler'dır. Wabt, bu insan tarafından okunabilir biçimi tekrar ikili wasm modülüne dönüştürmenize olanak tanıyan wat2wasm değerini de içerir. WebAssembly dosyalarımızı incelemek için bu iki tamamlayıcı aracı kullandık ancak en faydalı olanı wasm-strip bulduk. wasm-strip, WebAssembly modülündeki gereksiz bölümleri ve meta verileri kaldırır:

$ wasm-strip rotate_bg.wasm

Bu işlem, rust modülünün dosya boyutunu 7,5 KB'tan 6,6 KB'ya (gzip'ten sonra) düşürür.

wasm-opt

wasm-opt, Binaryen'in bir aracıdır. Bir WebAssembly modülü alır ve yalnızca bayt koduna göre hem boyut hem de performans açısından optimize etmeye çalışır. Emscripten gibi bazı araçlar bu aracı zaten çalıştırırken bazıları çalıştırmaz. Bu araçları kullanarak biraz daha bayt tasarrufu yapmaya çalışmak genellikle iyi bir fikirdir.

wasm-opt -O3 -o rotate_bg_opt.wasm rotate_bg.wasm

wasm-opt ile gzip'ten sonra toplam 6,2 KB olacak şekilde birkaç bayt daha azaltabiliriz.

#![no_std]

Bazı danışmanlık ve araştırmalardan sonra Rust'ın standart kitaplığını kullanmadan Rust kodumuzu #![no_std] özelliğini kullanarak yeniden yazdık. Bu işlem, dinamik bellek atamalarını da tamamen devre dışı bırakarak ayırıcı kodunu modülümüzden kaldırır. Bu Rust dosyasını şu sürümle derleyin:

$ rustc --target=wasm32-unknown-unknown -C opt-level=3 -o rust.wasm rotate.rs

wasm-opt, wasm-strip ve gzip'ten sonra 1,6 KB boyutunda bir wasm modülü elde edildi. C ve AssemblyScript tarafından oluşturulan modüllerden hâlâ daha büyük olsa da hafif kabul edilecek kadar küçüktür.

Performans

Yalnızca dosya boyutuna dayalı sonuçlara varmadan önce, bu yolculuğa dosya boyutunu değil performansı optimize etmek için çıktık. Peki performansı nasıl ölçtük ve sonuçlar ne oldu?

Karşılaştırma yapma

WebAssembly düşük düzey bir bayt kodu biçimi olmasına rağmen, ana makineye özgü makine kodu oluşturmak için bir derleyici üzerinden gönderilmesi gerekir. JavaScript gibi derleyici de birden fazla aşamada çalışır. Basitçe söylemek gerekirse: İlk aşama derleme işlemini çok daha hızlı gerçekleştirir ancak daha yavaş kod üretme eğilimindedir. Modül çalışmaya başladıktan sonra tarayıcı, sık kullanılan bölümleri gözlemler ve bunları daha optimize edilmiş ancak daha yavaş bir derleyiciden gönderir.

Kullanım alanımızın ilginç yanı, bir resmi döndürme kodunun bir kez, belki de iki kez kullanılacak olmasıdır. Bu nedenle, çoğu durumda optimize edici derleyicinin avantajlarından yararlanamayız. Karşılaştırma yaparken bunu göz önünde bulundurmak önemlidir. WebAssembly modüllerimizi bir döngüde 10.000 kez çalıştırmak gerçekçi olmayan sonuçlar verir. Gerçekçi sayılar elde etmek için modülü bir kez çalıştırıp tek bir çalıştırmadan elde edilen sayılara göre karar vermeliyiz.

Performans karşılaştırması

Dile göre hız karşılaştırması
Tarayıcı başına hız karşılaştırması

Bu iki grafik, aynı verilere ait farklı görünümlerdir. İlk grafikte tarayıcılara göre, ikinci grafikte ise kullanılan dile göre karşılaştırma yaparız. Lütfen logaritmik bir zaman ölçeği seçtiğimi unutmayın. Aynı makinede çalıştırılamayacak tek tarayıcı dışındaki tüm karşılaştırmalarda aynı 16 megapiksel test resminin ve aynı ana makinenin kullanılması da önemlidir.

Bu grafikleri çok fazla analiz etmeden, orijinal performans sorunumuzu çözdüğümüz açıktır: Tüm WebAssembly modülleri yaklaşık 500 ms veya daha kısa sürede çalışır. Bu, başlangıçta belirttiğimizi doğrular: WebAssembly, tahmin edilebilir performans sağlar. Hangi dili seçersek seçelim, tarayıcılar ve diller arasındaki farklılık minimumdur. Daha doğrusu: Tüm tarayıcılarda JavaScript'in standart sapması yaklaşık 400 ms, tüm tarayıcılarda tüm WebAssembly modüllerimizin standart sapması ise yaklaşık 80 ms'dir.

Yapılması gerekenler

Diğer bir metrik de WebAssembly modülümüzü oluşturup squoosh'a entegre etmek için harcamamız gereken çaba miktarıdır. Çalışmaya sayısal bir değer atamak zor olduğundan herhangi bir grafik oluşturmayacağım ancak vurgulamak istediğim birkaç nokta var:

AssemblyScript sorunsuzdu. Bu araç, WebAssembly yazmak için TypeScript'i kullanmanıza olanak tanıyarak iş arkadaşlarım için kod incelemesini çok kolaylaştırıyor. Ayrıca, iyi performansa sahip çok küçük, yapıştırıcı içermeyen WebAssembly modülleri oluşturuyor. TypeScript ekosistemindeki araçlar (ör. prettier ve tslint) büyük olasılıkla sorunsuz çalışır.

wasm-pack ile birlikte Rust da son derece kullanışlıdır ancak özellikle bağlama ve bellek yönetiminin gerekli olduğu daha büyük WebAssembly projelerinde daha iyi performans gösterir. Rekabetçi bir dosya boyutuna ulaşmak için en iyi yoldan biraz sapmamız gerekti.

C ve Emscripten, kutudan çıkar çıkmaz çok küçük ve yüksek performanslı bir WebAssembly modülü oluşturdu ancak yapıştırma koduna atlayıp bunu en temel ihtiyaçlara indirgeme cesareti olmadan toplam boyut (WebAssembly modülü + yapıştırma kodu) oldukça büyük oluyor.

Sonuç

JS sıcak yolunuz varsa ve bunu WebAssembly ile daha hızlı veya daha tutarlı hale getirmek istiyorsanız hangi dili kullanmalısınız? Performansla ilgili sorularda olduğu gibi, yanıt şudur: Duruma bağlı. Peki ne gönderdik?

Karşılaştırma grafiği

Kullandığımız farklı dillerin modül boyutu / performans dengesi açısından karşılaştırıldığında en iyi seçenek C veya AssemblyScript gibi görünüyor. Rust'u kullanıma sunmaya karar verdik. Bu kararın birden fazla nedeni vardır: Squoosh'ta şu ana kadar kullanıma sunulan tüm codec'ler Emscripten kullanılarak derlenmiştir. WebAssembly ekosistemi hakkındaki bilgilerimizi genişletmek ve üretimde farklı bir dil kullanmak istedik. AssemblyScript güçlü bir alternatiftir ancak proje nispeten genç ve derleyici, Rust derleyicisi kadar gelişmiş değildir.

Rust ile diğer diller arasındaki dosya boyutu farkı, dağılım grafiğinde oldukça belirgin görünse de gerçekte bu kadar büyük bir fark yoktur: 2 GB'ta bile 500 B veya 1,6 KB yüklemek saniyenin 1/10'undan kısa sürer. Rust'ın modül boyutu açısından bu farkı yakında kapatacağını umuyoruz.

Rust, çalışma zamanı performansı açısından tarayıcılarda AssemblyScript'ten daha hızlı bir ortalamaya sahiptir. Özellikle daha büyük projelerde Rust, manuel kod optimizasyonlarına ihtiyaç duymadan daha hızlı kod üretme olasılığı daha yüksektir. Ancak bu, en rahat kullandığınız yöntemi kullanmanıza engel olmamalıdır.

Tüm bunlara rağmen AssemblyScript harika bir keşif oldu. Web geliştiricilerinin yeni bir dil öğrenmek zorunda kalmadan WebAssembly modülleri oluşturmasına olanak tanır. AssemblyScript ekibi çok hızlı yanıt veriyor ve araç zincirlerini iyileştirmek için aktif olarak çalışıyor. Gelecekte AssemblyScript'i kesinlikle takip edeceğiz.

Güncelleme: Pas

Bu makale yayınlandıktan sonra Rust ekibinden Nick Fitzgerald, dosya boyutunu optimize etmeyle ilgili bir bölüm içeren mükemmel Rust Wasm kitaplarını bize önerdi. Buradaki talimatları uygulamak (özellikle de bağlantı zamanında optimizasyonları ve manuel panik yönetimi özelliklerini etkinleştirmek) "normal" Rust kodu yazmamıza ve dosya boyutunu şişirmeden Cargo (Rust'un npm) kullanmaya geri dönmemize olanak tanıdı. Rust modülü, gzip'ten sonra 370 B olur. Ayrıntılar için lütfen Squoosh'ta açtığım PR'ye göz atın.

Bu yolculukta bize destek olan Ashley Williams, Steve Klabnik, Nick Fitzgerald ve Max Graey'e özel teşekkürler.