WebAssembly özellik algılama

Kullanıcıları tüm tarayıcılarda desteklerken en yeni WebAssembly özelliklerini nasıl kullanacağınızı öğrenin.

Ingvar Stepanyan
Ingvar Stepanyan

WebAssembly 1.0 dört yıl önce piyasaya sürüldü, ancak geliştirmeler bununla bitmedi. Yeni özellikler teklif standartlaştırma süreciyle eklenir. Web'deki yeni özelliklerde genel olarak olduğu gibi, bunların uygulanma sırası ve zaman çizelgeleri, farklı motorlar arasında önemli ölçüde farklılık gösterebilir. Bu yeni özellikleri kullanmak istiyorsanız hiçbir kullanıcınızın dışarıda bırakılmadığından emin olmanız gerekir. Bu makalede, bunu başarmak için uygulanacak bir yaklaşım açıklanmaktadır.

Bazı yeni özellikler, genel işlemler için yeni talimatlar ekleyerek kod boyutunu iyileştirir, bazıları güçlü performans temel öğeleri ekler, diğerleri ise geliştirici deneyimini ve web'in geri kalanıyla entegrasyonu iyileştirir.

Tekliflerin tam listesini ve ilgili aşamalarını resmi depoda bulabilir veya resmi özellik yol haritası sayfasından bunların motorlardaki uygulama durumunu takip edebilirsiniz.

Uygulamanızı tüm tarayıcı kullanıcılarının kullanabilmesini sağlamak için hangi özellikleri kullanmak istediğinizi belirlemeniz gerekir. Daha sonra bunları tarayıcı desteğine göre gruplara ayırın. Daha sonra bu grupların her biri için kod tabanınızı ayrı ayrı derleyin. Son olarak, tarayıcı tarafında, desteklenen özellikleri tespit etmeniz ve ilgili JavaScript ile Wasm paketini yüklemeniz gerekir.

Seçme ve gruplandırma özellikleri

Örnek olarak rastgele bir özellik kümesi seçerek bu adımların üzerinden geçelim. Boyut ve performansla ilgili nedenlerle kitaplığımda SIMD, iş parçacıkları ve istisna işleme kullanmak istediğimi belirlediğimi varsayalım. Tarayıcı desteği aşağıdaki gibidir:

Seçilen özelliklerin tarayıcı desteğini gösteren bir tablo.
Bu özellik tablosunu webassembly.org/roadmap adresinden inceleyebilirsiniz.

Her kullanıcının en iyi şekilde optimize edilmiş deneyimi elde etmesini sağlamak için tarayıcıları aşağıdaki gruplara bölebilirsiniz:

  • Chrome tabanlı tarayıcılar: Threads, SIMD ve istisna işleme desteklenir.
  • Firefox: Thread ve SIMD desteklenir, istisna işleme desteklenmez.
  • Safari: İleti dizileri desteklenir, SIMD ve istisna işleme desteklenmez.
  • Diğer tarayıcılar: Yalnızca temel WebAssembly desteği olduğunu varsayın.

Bu döküm, her tarayıcının en son sürümündeki özellik desteğine göre ayrılır. Modern tarayıcılar her zaman güncel kalır ve otomatik olarak güncellenir. Bu nedenle, çoğu durumda yalnızca en son sürüm konusunda endişelenmeniz gerekir. Ancak, temel WebAssembly grubunu yedek kohort olarak dahil ettiğiniz sürece eski tarayıcılara sahip kullanıcılar için bile çalışan bir uygulama sağlayabilirsiniz.

Farklı özellik grupları için derleme

WebAssembly'nin, çalışma zamanında desteklenen özellikleri algılamak için yerleşik bir yöntemi yoktur. Bu nedenle, modüldeki tüm talimatlar hedefte desteklenmelidir. Bu nedenle, bu farklı özellik kümelerinin her biri için kaynak kodu Wasm'da ayrı ayrı derlemeniz gerekir.

Her araç zinciri ve yapı sistemi farklıdır ve bu özellikleri nasıl değiştireceğiniz konusunda kendi derleyicinizin dokümanlarına bakmanız gerekir. Basitlik sağlaması için aşağıdaki örnekte tek dosyalık bir C++ kitaplığı kullanacak ve Emscripten ile nasıl derleneceğini göstereceğim.

SIMD'yi SSE2 emülasyonu üzerinden ve Pthreads kitaplık desteğiyle ileti dizileri kullanıp Wasm istisna işleme ile yedek JavaScript uygulaması arasında seçim yapacağım:

# First bundle: threads + SIMD + Wasm exceptions
$ emcc main.cpp -o main.threads-simd-exceptions.mjs -pthread -msimd128 -msse2 -fwasm-exceptions
# Second bundle: threads + SIMD + JS exceptions fallback
$ emcc main.cpp -o main.threads-simd.mjs -pthread -msimd128 -msse2 -fexceptions
# Third bundle: threads + JS exception fallback
$ emcc main.cpp -o main.threads.mjs -pthread -fexceptions
# Fourth bundle: basic Wasm with JS exceptions fallback
$ emcc main.cpp -o main.basic.mjs -fexceptions

C++ kodunun kendisi, aynı işlevlerin paralel (iş parçacıkları ve SIMD) uygulamaları ile derleme zamanında seri uygulamaları arasında koşullu olarak seçim yapmak için #ifdef __EMSCRIPTEN_PTHREADS__ ve #ifdef __SSE2__ öğelerini kullanabilir. Kod şöyle görünür:

void process_data(std::vector<int>& some_input) {
#ifdef __EMSCRIPTEN_PTHREADS__
#ifdef __SSE2__
  // …implementation using threads and SIMD for max speed
#else
  // …implementation using threads but not SIMD
#endif
#else
  // …fallback implementation for browsers without those features
#endif
}

İstisna işleme, derleme işaretleri aracılığıyla seçilen temel uygulamadan bağımsız olarak C++ ile aynı şekilde kullanılabileceği için #ifdef yönergelerini gerektirmez.

Doğru paket yükleniyor

Tüm özellik kohortları için paketler oluşturduktan sonra, ana JavaScript uygulamasından doğru paketi yüklemeniz gerekir. Bunu yapmak için öncelikle mevcut tarayıcıda hangi özelliklerin desteklendiğini tespit edin. Bu işlemi wasm-feature-detect kitaplığıyla yapabilirsiniz. Bunu dinamik içe aktarma ile birleştirerek, herhangi bir tarayıcıda en optimize edilen paketi yükleyebilirsiniz:

import { simd, threads, exceptions } from 'https://unpkg.com/wasm-feature-detect?module';

let initModule;
if (await threads()) {
  if (await simd()) {
    if (await exceptions()) {
      initModule = import('./main.threads-simd-exceptions.mjs');
    } else {
      initModule = import('./main.threads-simd.mjs');
    }
  } else {
    initModule = import('./main.threads.mjs');
  }
} else {
  initModule = import('./main.basic.mjs');
}

const Module = await initModule();
// now you can use `Module` Emscripten object like you normally would

Son kelimeler

Bu gönderide, farklı özellik grupları için paketlerin nasıl seçileceğini, oluşturulacağını ve aralarında nasıl geçiş yapılacağını göstereceğim.

Özellik sayısı arttıkça özellik gruplarının sayısı yönetilemez hale gelebilir. Bu sorunu hafifletmek için gerçek dünyadaki kullanıcı verilerinizi temel alarak özellik kohortlarını seçebilir, daha az popüler olan tarayıcıları atlayabilir ve bu tarayıcıların optimum düzeyi biraz daha düşük olan grupları kullanmalarına izin verebilirsiniz. Uygulamanız hâlâ tüm kullanıcılar için çalıştığı sürece, bu yaklaşım progresif geliştirme ve çalışma zamanı performansı arasında makul bir denge sağlayabilir.

Gelecekte WebAssembly, desteklenen özellikleri algılamak ve modül içindeki aynı işlevin farklı uygulamaları arasında geçiş yapmak için yerleşik bir yönteme sahip olabilir. Ancak böyle bir mekanizmanın kendisi de MVP sonrası bir özellik olabilir. Yukarıdaki yaklaşımdan yararlanarak tespit edip koşullu olarak yüklemeniz gerekir. O zamana kadar bu yaklaşım, tüm tarayıcılarda yeni WebAssembly özelliklerini kullanarak kod oluşturmanın ve yüklemenin tek yolu olarak kalacak.