WebAssembly. Moc ukryta w przeglądarce (i nie tylko)
Wiedzieliście, że WebAssembly jest wykorzystywane w rozwoju aplikacji blockchain? Że pomimo swojego młodego wieku na wielu płaszczyznach prześciga w wydajności JavaScript i asm.js? Zdajecie sobie sprawę z tego, że Wasze aplikacje napisane w C czy C++ mogą trafić do przeglądarek bez przepisywania ich do Javascriptu? Wiecie, że w aplikacji, której kod jest rozwijany od 30 lat, już się to udało dzięki WASM? A może myśleliście o tym, by udostępnić Waszą grę, napisaną w Unity albo Unreal Engine, szerszej publiczności przez przeglądarki?
Mariusz Miszuta. Frontend Developer w RST Software Masters. Doświadczony programista JavaScript / PHP w branżach e-learningu i przemysłu transportowego. Pracuje w React.js, Redux, Node.js, Symfony, Docker, Ansible and Puppet.
Spis treści
Trochę historii…
JavaScript to język stworzony w 1995 roku przez Brendana Eicha pracującego wówczas dla Netscape. Stanowi monopolistę w kategorii języków programowania obsługiwanych przez przeglądarki. JavaScript pokonał niesamowitą drogę, by stać się językiem, jakim jest dziś. Silniki takie, jak np. Chrome V8, dokonują cudów w zakresie optymalizacji kodu skompilowanego w momencie jego wywołania (JIT – just-in-time compilation), jednak JavaScriptowi wciąż trudno jest osiągnąć natywną wydajność w aplikacjach sieciowych.
W 2013 roku Mozilla wydała na świat asm.js, czyli podzbiór JavaScriptu zawierający minimalistyczny zestaw funkcji (np. nie zawierała pętli “for”), który zapewniał lepszą wydajność przez kompilację przed uruchomieniem oraz statyczne typowanie.
Potrzeba wydajności
Ostatnie lata przyniosły wiele technologii, które rozwijają się w zastraszającym tempie. Trendy panujące wśród użytkowników sugerują rosnącą potrzebę mobilności i “stałego dostępu” do ulubionych platform i aplikacji. W 2016 roku liczba użytkowników łączących się z Internetem przez urządzenia mobilne przerosła liczbę osób wykorzystujących komputery. Dostęp do aplikacji tylko w domu, na komputerze stacjonarnym, powoli odchodzi do lamusa. Dokumenty Microsoft Excel czy Word można już edytować w Sieci. Przeglądarki stały się swego rodzaju systemami operacyjnymi. Świat przenosi się do Internetu, jednak aby było to możliwe, potrzebna jest wydajność.
Odpowiadając na potrzeby użytkowników i developerów, w marcu 2017 roku spod skrzydeł W3C wyszedł WebAssembly (WASM) — drugi po JavaScript język programowania w historii (i jednocześnie pierwszy język binarny) obsługiwany przez przeglądarki.
Natywna wydajność dla każdego
Na pewno każdy pamięta Adobe Flash, aplety Java czy nie tak odległy PNaCL (Portable Native Client), czyli próby podbicia Internetu przez inną od JavaScriptu technologię. To, czym WebAssembly odróżnia się od wyżej wymienionych, jest fakt, że WASM jest wbudowany w przeglądarki, tak jak JavaScript, i znajduje się oficjalnie w standardzie Sieci wydawanym przez W3C. Flash i Java applets operowały na wtyczkach, nigdy nie stanowiły integralnej części przeglądarek, były jedynie sztucznie “doklejonym” tworem.
PNaCL dostępny jest natomiast tylko w przeglądarce Chrome. Google od ponad roku pracuje, by Google Earth zostało przeniesione z ich technologii PNaCL do WebAssembly, podwyższając tym samym wydajność i przede wszystkim pozwalając użytkownikom na korzystanie ze swojego produktu w każdej przeglądarce. Otwiera to cały wachlarz możliwości firmom tworzącym dotychczas aplikacje ograniczone do środowiska, dla którego zostały napisane.
Jak Autodesk wykorzystał WebAssembly
Doskonałym przykładem wykorzystania WebAssembly jest Autodesk, który wielokrotnie próbował zaistnieć ze swoim flagowym produktem Autocad w przeglądarce. Prób było kilka (Flash, HTML5+JavaScript), jednak koszty, jakich wymaga przeniesienie w całości kodu tak potężnego produktu, jakim jest Autocad, oraz wydajność, jaka jest potrzebna, by można było osiągnąć jego płynne działanie w przeglądarce, stawały ością w gardle ekipie Autodesk. Już teraz webowa wersja Autocada wykorzystuje swój silnik napisany w C++, przekompilowany do WebAssembly, unikając tym samym niewiadomej, jaką jest potencjalna wydajność aplikacji przepisanej do JavaScriptu. Tę nieprzewidywalność JavaScriptu dobrze obrazuje poniższy diagram.
Źródło grafiki: hacks.mozilla.org
Poza przewagą wydajnościową WebAssembly, wykres pokazuje też odchylenia, jakie występują przy każdym kolejnym wywołaniu kodu. Testowana jest wydajność przy odnajdywaniu wyjątków w mapie kodu źródłowego (narzędzie przeglądarki do debugowania kodu, które znacznie przyspiesza pracę programisty).
Ważnym aspektem są także koszty. WebAssembly pozwala wykorzystać już napisany kod i przekompilować go tak, by był zrozumiały dla przeglądarek.
Autodesk to nie wyjątek
Kolejnymi przykładami dużych realizacji z wykorzystaniem WASM są Figma — aplikacja do projektowania interfejsów na wielu urządzeniach jednocześnie, oraz PSPDFKit, czyli aplikacja do generowania dokumentów PDF. Ich doświadczenia z WebAssembly opisuję szerzej w kontekście benchmarków.
Idea płynąca z WebAssembly wykracza poza portowanie aplikacji napisanych w niskopoziomowych językach na przeglądarki. Wystarczy spojrzeć na Nebulet — projekt systemu operacyjnego z modułami WebAssembly oraz kompilatorem WASM do kodu maszynowego. Możemy zatem spodziewać się, że WASM nie tylko zagości na stałe w przeglądarkach, lecz także natywnie na urządzeniach, otwierając możliwości chociażby dla Internet of Things (IoT).
Benchmarki
Część z wymienionych wyżej firm także zdecydowało się opisać swoje doświadczenia z WebAssembly i zmierzyć wzrost wydajności po przejściu na WASM. Wyniki udostępnione przez Figmę mówią same za siebie.
Źródło grafik: blog.figma.com
Załadowanie dużego projektu w przeglądarkowej aplikacji zajęło ponad 3-krotnie mniej czasu w WASM niż przy kompilacji do jego protoplasty.
PSPDFKit również udostępnili na blogu wyniki benchmarków dla swojego silnika złożonego z 500.000+ linii kodu w C++, który dzięki WASM uruchamiany jest w przeglądarce
Źródło grafik: pspdfkit.com
Powyższe wykresy uświadamiają, że choć jeszcze długa droga przed programistami odpowiedzialnymi za obsługę WASM w przeglądarce, już teraz widać możliwości, jakie daje ten język. Ponad dwukrotnie lepszy wynik WASM (Firefox 61) od najlepszego wyniku JavaScript (Chrome 67) to naprawdę duże osiągnięcie.
Nie znaczy to, że JavaScript odejdzie w niepamięć wraz z rozpowszechnieniem WASM. Wciąż jest to wydajny język, który pozwala szybko generować kod i wspaniale sprawdza się przy manipulacji drzewem DOM. WebAssembly uzupełnia JavaScript w tych miejscach, w których potrzeba surowej mocy obliczeniowej. Żadna z wymienionych wyżej firm nie zrezygnowała z JS-a i budowała interfejs użytkownika właśnie w oparciu o JavaScript/Typescript.
Obiecująca technologia, ale…
WebAssembly jest bardzo młodą technologią i jeszcze wiele pracy czeka programistów stojących za projektem.
W tym momencie z kompilacją do WebAssembly najlepiej radzą sobie języki Rust, C i C++. Łączy je przede wszystkim jedna cecha wspólna — ręczne zarządzanie pamięcią.
WebAssembly wciąż pracuje nad dodaniem garbage collectora czy obsługi wątków, co na pewno ułatwi kompilację najpopularniejszych języków wykorzystywanych w dużych korporacjach, tj. Javy i C#. Oczywiście kompilatory są już dostępne (TeaVM czy JWebAssembly w przypadku Javy, Blazor w przypadku C#), jednak ich możliwości są na ten moment ograniczone.
Kolejnym problemem jest dostęp WASM do drzewa DOM. Ta funkcjonalność wciąż wymusza użycia kodu JavaScript, jednak twórcy pracują nad tym, by było to możliwe (tu więcej na ten temat). Oczywiście nic nie stoi na przeszkodzie, by już teraz przenieść wymagającą logikę do WASM, a manipulację drzewem DOM i wizualną reprezentację aplikacji pozostawić JavaScriptowi, który na ten moment wciąż pozostaje w tej dziedzinie numerem jeden.
Na szczęście WASM i Javascript doskonale się uzupełniają, a środowisko JS pozwala na łatwą integrację modułów WebAssembly. Najpopularniejsze bundlery, takie jak Webpack czy parcel, wspierają WASM (Webpack od wersji 4, Parcel od v1.5). Oczywiście puryści języka Javascript, którzy chcieliby skorzystać z dobrodziejstw WebAssembly, nie są skazani na bundlery, ponieważ mają do dyspozycji udostępniony natywnie namespace WebAssembly, który daje możliwość importowania synchronicznego i asynchronicznego modułów WASM.
Podsumowując, krokami milowymi w rozwoju WASM będą:
- Garbage Collector
- Bezpośredni dostęp do Browser API i drzewa DOM
Czy warto?
Webassembly jest już wspierany przez Golang — język rozwijany przez Google. Jest to ważna informacja, ponieważ Portable Native Client już od pierwszego kwartału 2018 przestał być rozwijany na rzecz WASM.
Microsoft także dostrzega potencjał języka, dlatego też Kompilator C# stworzony dla WebAssembly, Blazor, znajduje się pod jego skrzydłami.
Wsparcie przeglądarek również przedstawia się obiecująco:
Już ponad ¾ użytkowników może korzystać z WebAssembly, natomiast w przypadku, gdy przeglądarka nie wspiera kodu WASM, można tak skonfigurować kompilator, aby udostępnił kod w wersji poprzednika WASM, czyli asm.js.
Na jednym ze spotkań społeczności skupionej wokół WebAssembly, dotyczących przyszłych planów, poruszony został temat przejścia przeglądarki Edge na Chromium i tym samym na silnik v8. Wstępnie zdecydowano, że WASM wciąż będzie rozwijany także dla silnika ChakraCore.
Moim zdaniem, wszystko wskazuje na to, że świat potrzebuje WebAssembly i dąży do tego, by jak najszybciej wpisał się w kanon Web Developmentu. Dostajemy do ręki narzędzie, które daje nam olbrzymie możliwości i osobiście nie mogę się doczekać dużego projektu, dla którego rozwiązaniem będzie właśnie WebAssembly. Teraz, gdy na horyzoncie majaczą już blockchain i machine learning, myślę, że nie będę musiał czekać długo.
Zdjęcie główne artykułu pochodzi z pexels.com.