WebAssembly özellik algılama

Kullanıcıları tüm tarayıcılarda desteklerken en yeni WebAssembly özelliklerini kullanmayı öğrenin.

Ingvar Stepanyan
Ingvar Stepanyan

WebAssembly 1.0 dört yıl önce yayınlandı ancak geliştirme süreci bununla sınırlı değil. Yeni özellikler teklif standartlaştırma süreci ile eklenir. Web'deki yeni özelliklerde genellikle olduğu gibi, bunların uygulanma sıraları ve zaman çizelgeleri farklı motorlarda ö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şarmaya yönelik bir yaklaşım öğreneceksiniz.

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

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

Tüm tarayıcılardaki kullanıcıların uygulamanızı kullanabildiğinden emin olmak için hangi özellikleri kullanmak istediğinizi belirlemeniz gerekir. Daha sonra bunları tarayıcı desteğine göre gruplara ayırın. Ardından, 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 ve Wasm paketini yüklemeniz gerekir.

Seçme ve gruplandırma özellikleri

Örnek olarak rastgele bir özellik seçerek bu adımların üzerinden geçelim. Boyut ve performans nedeniyle kitaplığımda SIMD, ileti dizileri ve istisna işleme özelliklerini kullanmak istediğ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 adresinde görüntüleyebilirsiniz.

Her kullanıcının en iyi şekilde optimize edilmiş deneyim yaşamasını sağlamak için tarayıcıları aşağıdaki gruplara ayırabilirsiniz:

  • Chrome tabanlı tarayıcılar: İleti dizileri, SIMD ve istisna işlemenin tümü 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ğini varsayın.

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

Farklı özellik kümeleri için derleme

WebAssembly, çalışma zamanında desteklenen özellikleri algılamak için yerleşik bir yönteme sahip olmadığından modüldeki tüm talimatlar hedefte desteklenmelidir. Bu nedenle, bu farklı özellik gruplarının her biri için kaynak kodunu Wasm'da ayrı ayrı derlemeniz gerekir.

Her araç zinciri ve derleme sistemi farklıdır ve bu özellikleri nasıl düzenleyeceğinizi öğrenmek için kendi derleyicinizin dokümanlarına bakmanız gerekir. Basit olması için aşağıdaki örnekte tek dosyalı bir C++ kitaplığı kullanacağım ve bu kitaplığın Emscripten ile nasıl derleneceğini göstereceğim.

SSE2 emülasyonu aracılığıyla SIMD'yi, Pthreads kitaplık desteği üzerinden ileti dizilerini kullanacağım ve 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

Aynı işlevlerin paralel (iş parçacıkları ve SIMD) uygulamaları ile derleme sırasında seri uygulamaları arasında koşullu olarak seçim yapmak için C++ kodunun kendisi #ifdef __EMSCRIPTEN_PTHREADS__ ve #ifdef __SSE2__ kullanabilir. Bu 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
}

Derleme işaretleri, derleme işaretleri aracılığıyla seçilen temel uygulamadan bağımsız olarak, C++ ile aynı şekilde kullanılabildiğinden istisna işleme için #ifdef yönergeleri gerekmez.

Doğru paket yükleniyor

Tüm özellik grupları için paket oluşturduktan sonra ana JavaScript uygulamasından doğru paketi yüklemeniz gerekir. Bunun için önce mevcut tarayıcıda hangi özelliklerin desteklendiğini tespit etmeniz gerekir. Bu işlemi wasm-feature-detect kitaplığıyla yapabilirsiniz. Dinamik içe aktarma ile birleştirerek en iyi optimize edilmiş paketi tüm tarayıcılarda 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 setleri için paket seçme, oluşturma ve paketler arasında geçiş yapma konularını gösterdim.

Özelliklerin sayısı arttıkça özellik gruplarının sayısı da devam ettirilemez hale gelebilir. Bu sorunu hafifletmek için gerçek kullanıcı verilerinize dayalı özellik kohortları seçebilir, daha az popüler olan tarayıcıları atlayabilir ve biraz daha az optimum olan kohortlara geri dönmelerini sağlayabilirsiniz. Uygulamanız tüm kullanıcılar için çalışmaya devam ettiği sürece bu yaklaşım, aşamalı geliştirme ve çalışma zamanı performansı arasında makul bir denge sağlayabilir.

Gelecekte WebAssembly, desteklenen özellikleri algılamak ve modül içinde aynı işlevin farklı uygulamaları arasında geçiş yapmak için yerleşik bir yönteme sahip olabilir. Ancak böyle bir mekanizma, yukarıdaki yaklaşımı kullanarak koşullu olarak tespit edip yüklemeniz gereken MVP sonrası bir özellik olacaktır. O zamana kadar bu yaklaşım, tüm tarayıcılarda yeni WebAssembly özelliklerini kullanarak kod derlemenin ve yüklemenin tek yolu olarak kalmaya devam edecek.