WebAssembly özellik algılama

Tüm tarayıcılarda kullanıcıları desteklerken en yeni WebAssembly özelliklerini nasıl kullanacağınızı öğ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 aracılığıyla eklenir. Web'deki yeni özelliklerde genellikle olduğu gibi, bu özelliklerin uygulama 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ş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ı güçlü performans temel öğeleri ekler, bazıları ise geliştirici deneyimini ve web'in geri kalanıyla entegrasyonu iyileştirir.

Önerilerin tam listesini ve ilgili aşamalarını resmi depoda bulabilir veya resmi özellik yol haritası sayfasında motorlardaki uygulama durumlarını takip edebilirsiniz.

Tüm tarayıcıların kullanıcılarının uygulamanızı kullanabilmesini sağlamak için hangi özellikleri kullanmak istediğinizi belirlemeniz gerekir. Ardından, 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 algılamanız ve ilgili JavaScript ve Wasm paketini yüklemeniz gerekir.

Özellikleri seçme ve gruplandırma

Örnek olarak rastgele bir özellik kümesi seçerek bu adımları inceleyelim. Boyut ve performans nedeniyle kitaplığımda SIMD, iş parçacığı 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 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: İş parçacığı 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 varsayılır.

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ünceldir ve otomatik olarak güncellenir. Bu nedenle, çoğu durumda yalnızca en son sürümle ilgilenmeniz gerekir. Ancak, yedek kohort olarak referans WebAssembly'i eklediğiniz sürece, eski tarayıcılara sahip kullanıcılar için bile çalışan bir uygulama sunabilirsiniz.

Farklı özellik kümeleri için derleme

WebAssembly, çalışma zamanında desteklenen özellikleri algılamak için yerleşik bir yönteme sahip değildir. Bu nedenle, modüldeki tüm talimatlar hedefte desteklenmelidir. Bu nedenle, kaynak kodunu bu farklı özellik gruplarının her biri için ayrı olarak Wasm'e 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. Basitlik açısından 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, Pthreads kitaplığı desteği aracılığıyla iş parçacıkları ve Wasm istisna işleme ile yedek JavaScript uygulaması arasından 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++ kodu, derleme zamanında aynı işlevlerin paralel (iş parçacığı ve SIMD) uygulamaları ile seri uygulamaları arasında koşullu olarak seçim yapmak için #ifdef __EMSCRIPTEN_PTHREADS__ ve #ifdef __SSE2__ kullanabilir. Bu, aşağıdaki gibi 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++'tan aynı şekilde kullanılabildiğinden #ifdef yönergelerine ihtiyaç duymaz.

Doğru paketi yükleme

Tüm özellik grupları için paket 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. Bunu wasm-feature-detect kitaplığıyla yapabilirsiniz. Bu özelliği dinamik içe aktarma ile birleştirerek en optimize paketi herhangi bir tarayıcıda 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 paket seçme, oluşturma ve paketler arasında geçiş yapma konularını gösterdim.

Özellik sayısı arttıkça özellik kohortlarının sayısı sürdürülemeyebilir. Bu sorunu hafifletmek için gerçek kullanıcı verilerinize göre özellik kohortları seçebilir, daha az popüler tarayıcıları atlayabilir ve bu tarayıcıların biraz daha az optimal kohortlara geri dönmesine izin verebilirsiniz. Uygulamanız tüm kullanıcılar için çalışmaya devam ettiği sürece bu yaklaşım, aşamalı iyileştirme ile ç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 bu tür bir mekanizma, yukarıdaki yaklaşımı kullanarak koşullu olarak algılamanız ve yüklemeniz gereken bir MVP sonrası özellik olur. O zamana kadar bu yaklaşım, tüm tarayıcılarda yeni WebAssembly özelliklerini kullanarak kod derlemenin ve yüklemenin tek yolu olarak kaldı.