Dowiedz się, jak korzystać z najnowszych funkcji WebAssembly, obsługując użytkowników we wszystkich przeglądarkach.
Wersja 1.0 WebAssembly została wydana 4 lata temu, ale rozwój nie zatrzymał się na tym etapie. Nowe funkcje są dodawane w ramach procesu standaryzacji ofert. Jak to zwykle bywa w przypadku nowych funkcji w internecie, kolejność i terminy ich wdrażania mogą się znacznie różnić w zależności od silnika. Jeśli chcesz korzystać z tych nowych funkcji, musisz się upewnić, że żaden z użytkowników nie zostanie pominięty. Z tego artykułu dowiesz się, jak to zrobić.
Niektóre nowe funkcje poprawiają rozmiar kodu przez dodanie nowych instrukcji dotyczących typowych operacji, inne wprowadzają wydajne elementy, a jeszcze inne ułatwiają pracę programistom i integrację z resztą internetu.
Pełną listę propozycji i odpowiednich etapów znajdziesz w oficjalnym repozytorium. Stan ich implementacji w silnikach możesz śledzić na oficjalnej stronie mapy drogowej funkcji.
Aby użytkownicy wszystkich przeglądarek mogli korzystać z Twojej aplikacji, musisz określić, których funkcji chcesz użyć. Następnie podziel je na grupy na podstawie obsługi przez przeglądarki. Następnie skompiluj kod źródłowy osobno dla każdej z tych grup. Na koniec po stronie przeglądarki musisz wykryć obsługiwane funkcje i wczytać odpowiedni pakiet JavaScript i Wasm.
Wybieranie i grupowanie cech
Aby pokazać, jak to zrobić, weźmiemy pod uwagę dowolny zestaw funkcji. Załóżmy, że chcę używać w swojej bibliotece instrukcji SIMD, wątków i obsługi wyjątków ze względu na rozmiar i wydajność. Obsługa przeglądarek:

Aby zapewnić każdemu użytkownikowi optymalne wrażenia, możesz podzielić przeglądarki na te grupy:
- Przeglądarki oparte na Chrome: obsługiwane są wątki, instrukcje SIMD i obsługa wyjątków.
- Firefox: obsługiwane są wątki i SIMD, ale nie obsługa wyjątków.
- Safari: wątki są obsługiwane, ale SIMD i obsługa wyjątków nie są obsługiwane.
- Inne przeglądarki: zakłada się, że obsługują one tylko podstawową wersję WebAssembly.
Ten podział uwzględnia obsługę funkcji w najnowszej wersji każdej przeglądarki. Nowoczesne przeglądarki są zawsze aktualne i automatycznie się aktualizują, więc w większości przypadków wystarczy Ci najnowsza wersja. Jeśli jednak uwzględnisz podstawowy WebAssembly jako grupę awaryjnych użytkowników, nadal będziesz mieć działającą aplikację nawet dla użytkowników ze starszymi przeglądarkami.
Kompilowanie dla różnych zestawów funkcji
WebAssembly nie ma wbudowanego sposobu wykrywania obsługiwanych funkcji w czasie wykonywania, dlatego wszystkie instrukcje w module muszą być obsługiwane na urządzeniu docelowym. W związku z tym musisz skompilować kod źródłowy w Wasm osobno dla każdego z tych zestawów funkcji.
Każda toolchain i każdy system kompilacji są inne, więc aby dowiedzieć się, jak je dostosować, musisz zapoznać się z dokumentacją własnego kompilatora. W tym przykładzie użyję dla uproszczenia biblioteki C++ w jednym pliku i pokażę, jak ją skompilować za pomocą Emscripten.
Użyję SIMD za pomocą emulacji SSE2, wątków za pomocą obsługi biblioteki Pthreads oraz obsługi wyjątków Wasm lub implementacji JavaScriptu:
# 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
Sam kod C++ może używać funkcji #ifdef __EMSCRIPTEN_PTHREADS__
i #ifdef __SSE2__
, aby warunkowo wybierać implementacje tych samych funkcji (wątek i SIMD) i implementacje sekwencyjne w czasie kompilacji. Wygląda to tak:
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
}
Obsługa wyjątków nie wymaga dyrektyw #ifdef
, ponieważ można jej używać w taki sam sposób w C++, niezależnie od implementacji wybranej za pomocą flag kompilacji.
Wczytywanie prawidłowego pakietu
Po utworzeniu pakietów dla wszystkich grup funkcji musisz wczytać odpowiedni z głównej aplikacji JavaScript. Aby to zrobić, najpierw sprawdź, które funkcje są obsługiwane w bieżącej przeglądarce. Możesz to zrobić za pomocą biblioteki wasm-feature-detect. Połączenie go z importem dynamicznym pozwala wczytać najbardziej zoptymalizowany pakiet w dowolnej przeglądarce:
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
Ostateczne słowa
W tym poście pokażę, jak wybierać, tworzyć i przełączać pakiety z różnymi zestawami funkcji.
W miarę wzrostu liczby cech może być niemożliwe utrzymanie odpowiedniej liczby kohort cech. Aby rozwiązać ten problem, możesz wybrać grupy funkcji na podstawie rzeczywistych danych o użytkownikach, pominąć mniej popularne przeglądarki i przełączyć się na nieco mniej optymalne grupy. Jeśli aplikacja nadal działa dla wszystkich użytkowników, to podejście może zapewnić odpowiednią równowagę między ulepszaniem progresywnym a wydajnością w czasie działania.
W przyszłości WebAssembly może uzyskać wbudowany sposób wykrywania obsługiwanych funkcji i przełączania się między różnymi implementacjami tej samej funkcji w module. Taki mechanizm byłby jednak funkcją dodaną po wersji MVP, którą trzeba by wykrywać i wczytywać warunkowo, korzystając z opisanego powyżej podejścia. Do tego czasu to podejście pozostaje jedynym sposobem kompilowania i wczytywania kodu przy użyciu nowych funkcji WebAssembly we wszystkich przeglądarkach.