WebAssembly ile çalışırken genellikle bir modülü indirip derlemek, örneklemek ve ardından dışa aktardığı her şeyi JavaScript'te kullanmak istersiniz. Bu yayında, optimum verimlilik için önerdiğimiz yaklaşım açıklanmaktadır.
WebAssembly ile çalışırken genellikle bir modülü indirmek, derlemek, örneklemek ve ardından JavaScript'te dışa aktardığı her şeyi kullanmak istersiniz. Bu gönderi, tam olarak bunu yapan yaygın ancak en uygun kod snippet'iyle başlar, çeşitli olası optimizasyonları tartışır ve sonunda WebAssembly'i JavaScript'ten çalıştırmanın en basit ve en verimli yolunu gösterir.
Bu kod snippet'i, indirme-derleme-oluşturma işlemini en uygun olmayan şekilde gerçekleştirir:
Bunu kullanmayın.
(async () => {
const response = await fetch('fibonacci.wasm');
const buffer = await response.arrayBuffer();
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
Bir yanıt arabelleğini modüle dönüştürmek için new WebAssembly.Module(buffer)
'ü nasıl kullandığımıza dikkat edin. Bu, senkronize bir API'dir. Yani, tamamlanana kadar ana iş parçacığını engeller. Chrome, kullanımını engellemek için 4 KB'tan büyük tamponlar için WebAssembly.Module
'ü devre dışı bırakır. Boyut sınırını aşmak için bunun yerine await WebAssembly.compile(buffer)
kullanabiliriz:
(async () => {
const response = await fetch('fibonacci.wasm');
const buffer = await response.arrayBuffer();
const module = await WebAssembly.compile(buffer);
const instance = new WebAssembly.Instance(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
await WebAssembly.compile(buffer)
hala ideal yaklaşım olmasa da birazdan bu konuyu ele alacağız.
await
kullanımı açıkça görüldüğünden, değiştirilen snippet'teki neredeyse her işlem artık eşzamansız. Bunun tek istisnası, Chrome'dakiyle aynı 4 KB arabellek boyutu kısıtlamasına sahip olan new WebAssembly.Instance(module)
'tir. Tutarlılık ve ana iş parçasını boş tutma için asenkron WebAssembly.instantiate(module)
kullanabiliriz.
(async () => {
const response = await fetch('fibonacci.wasm');
const buffer = await response.arrayBuffer();
const module = await WebAssembly.compile(buffer);
const instance = await WebAssembly.instantiate(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
Daha önce ipucu verdiğim compile
optimizasyonuna geri dönelim. Akışlı derleme sayesinde tarayıcı, modül baytları indirilirken bile WebAssembly modülünü derlemeye başlayabilir. İndirme ve derleme işlemi paralel olarak gerçekleştiğinden bu işlem, özellikle büyük yüklerde daha hızlıdır.
Bu optimizasyonu etkinleştirmek için WebAssembly.compile
yerine WebAssembly.compileStreaming
kullanın.
Bu değişiklik sayesinde await fetch(url)
tarafından döndürülen Response
örneğini doğrudan iletebildiğimiz için ara dizi arabelleğinden de kurtulabiliriz.
(async () => {
const response = await fetch('fibonacci.wasm');
const module = await WebAssembly.compileStreaming(response);
const instance = await WebAssembly.instantiate(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
WebAssembly.compileStreaming
API, Response
örneğine çözümlenen taahhütleri de kabul eder. Kodunuzun başka bir yerinde response
'ye ihtiyacınız yoksa sonucunu açıkça await
etmeden fetch
tarafından döndürülen vaadi doğrudan iletebilirsiniz:
(async () => {
const fetchPromise = fetch('fibonacci.wasm');
const module = await WebAssembly.compileStreaming(fetchPromise);
const instance = await WebAssembly.instantiate(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
fetch
sonucuna başka bir yerde ihtiyacınız yoksa doğrudan iletebilirsiniz:
(async () => {
const module = await WebAssembly.compileStreaming(
fetch('fibonacci.wasm'));
const instance = await WebAssembly.instantiate(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
Ancak şahsen ayrı bir satırda tutmayı daha okunaklı buluyorum.
Yanıtı nasıl modül halinde derleyip ardından hemen örneklendirdiğimizi öğrenin. WebAssembly.instantiate
tek seferde derleyip örneklendirebilir. WebAssembly.instantiateStreaming
API, bunu akış yöntemiyle yapar:
(async () => {
const fetchPromise = fetch('fibonacci.wasm');
const { module, instance } = await WebAssembly.instantiateStreaming(fetchPromise);
// To create a new instance later:
const otherInstance = await WebAssembly.instantiate(module);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
Yalnızca tek bir örneğe ihtiyacınız varsa module
nesnesini tutmanın bir anlamı yoktur. Bu durumda kodu daha da basitleştirebilirsiniz:
// This is our recommended way of loading WebAssembly.
(async () => {
const fetchPromise = fetch('fibonacci.wasm');
const { instance } = await WebAssembly.instantiateStreaming(fetchPromise);
const result = instance.exports.fibonacci(42);
console.log(result);
})();
Uyguladığımız optimizasyonlar şu şekilde özetlenebilir:
- Ana iş parçacığının engellenmesini önlemek için eşzamansız API'ler kullanın
- WebAssembly modüllerini daha hızlı derlemek ve örneklendirmek için akış API'lerini kullanın.
- İhtiyacınız olmayan kodlar yazmayın
WebAssembly ile eğlenin.