WebAssembly modüllerini verimli bir şekilde yükleme

WebAssembly ile çalışırken genellikle bir modül indirmek, derlemek, örneklendirmek ve ardından JavaScript'te dışa aktardığını 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, örneklendirmek ve daha sonra, JavaScript'e aktardığı şeyi kullanabilirsiniz. Bu gönderi, yaygın ancak ideal olmayan bir kodla başlıyor snippet'inin tam olarak bunu yaptığına dikkat edin, çeşitli olası optimizasyonları tartışır ve en sonunda WebAssembly'yi JavaScript'ten çalıştırmanın en basit ve en verimli yolunu sunar.

Bu kod snippet'i, indirme işlemlerini anında yapmak için gereken dansı mükemmel olmasa da mükemmel olmayan bir şekilde çalışır:

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) yöntemini nasıl kullandığımıza dikkat edin. Bu, eşzamanlı API'dir. Diğer bir deyişle, tamamlanana kadar ana iş parçacığını engeller. Chrome, kullanılmasını önlemek için 4 KB'tan büyük arabellekler için WebAssembly.Module öğesini devre dışı bırakır. Boyut sınırını aşmak için bunun yerine await WebAssembly.compile(buffer) kullanın:

(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 bunu bir şekilde ele alacağız. tıklayın.

Değiştirilen snippet'teki hemen hemen her işlem artık eşzamansız olduğundan, await kullanımı açık. Tek istisna, aynı 4 KB arabelleğine sahip olan new WebAssembly.Instance(module). Chrome'da boyut kısıtlaması var. Tutarlılık için ve ana ileti dizisini korumak amacıyla ücretsiz olarak ayarlayabiliriz. WebAssembly.instantiate(module).

(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ı bir derleme olarak sunuyorsanız, tarayıcı zaten modül baytları indirilmeye devam ederken WebAssembly modülünü derlemeye başlar. İndirildikten sonra Bu süreç, özellikle büyük yüklerde daha hızlı yapılır.

İndirme zamanı şu olduğunda:
daha uzun olduğunda, WebAssembly modülünün derleme süresinden daha uzun olduğunda
son baytlar indirildikten hemen sonra derlemeyi bitirir.

Bu optimizasyonu etkinleştirmek için WebAssembly.compile yerine WebAssembly.compileStreaming politikasını kullanın. Bu değişiklik, ara dizi tamponundan da kurtulmamızı sağlar. Çünkü artık Response örneği doğrudan await fetch(url) tarafından döndürüldü.

(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 ile çözümlenen bir taahhüdü de kabul eder. kullanır. Kodunuzda başka bir yerde response öğesine ihtiyaç duymuyorsanız verdiğiniz sözü iletebilirsiniz sonucu açık bir şekilde await vermeden, doğrudan fetch tarafından döndürülür:

(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);
})();

Yine de bunu ayrı bir satırda tutmak adına daha okunabilir olduğunu düşünüyorum.

Yanıtı nasıl modül halinde derlediğimizi ve ardından hemen nasıl örneklendirdiğimizi öğrenin. Sonuçta WebAssembly.instantiate tek seferde derleyip örnek verebilir. İlgili içeriği oluşturmak için kullanılan WebAssembly.instantiateStreaming API, bunu akış şeklinde 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 saklamanın bir anlamı yoktur. kodunu daha da basitleştirin:

// 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 aşağıdaki gibi özetlenebilir:

  • Ana iş parçacığını engellememek 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!