Zasada działania kompilatora i silnika w Javascript

0

Powiedzcie mi czy dobrze to rozumiem:

Zakładając, że pisze np aplikację w React w Visual Studio Code. Visual Studio Code ma wbudowany kompilator, więc kompiluje kod, a następnie odpalam aplikację w przeglądarce przy użyciu komendy npm start.
Przeglądarka korzysta z jakiegoś silnika do JavaScript, więc tylko wykonuje już ten skompilowany kod czy na nowo kompiluje kod, a następnie go wykonuje?

5

Odpalając npm start następuje transpilacja¹ kodu React do kodu JavaScript - wykonuje to toolchain od Reacta (w połączeniu z tsc?), nie Visual Studio Code.

Mając już kod JavaScriptowy, nowoczesne przeglądarki najczęściej² wykorzystują just in time compilation - tzn. zaczynają od interpretacji kodu JS (ew. szybkiej kompilacji do bajtkodu), następnie stopniowo kompilując jego części do kodu natywnego dla danej platformy.

(np. przeglądarka odpalona na Windowsie + DirectX + Intel zacznie kompilować oraz optymalizować kod pod tę platformę.)

Czyli taki ogólny flow graph wyglądałby tak:

React ("prawie JavaScript") -----> JavaScript -------> kod natywny
                         transpilacja        kompilacja
                                        (ew. interpretacja)

¹ formalnie termin kompilacja odnosi się do konwersji kodu w kod bardziej nisko-poziomowy (C++ -> assembly, Rust -> WebAssembly, Java -> JVM bytecode itd.) - konwersja kodu na język wyjściowy o podobnym poziomie abstrakcji jak język wejściowy (CoffeeScript -> JavaScript, TypeScript -> JavaScript itd.) nazywa się transpilacją

² citation needed

0

A możesz w skrócie opisać czym jest ten toolchain w Reacie?

1

Obawiam się, że nie rozumiem pytania; toolchain tutaj odnosi się właśnie do aplikacji, która transpiluje Reacta (JSX?) na JavaScript.

0

hmm to czemu aplikację nazywasz toolchainem? Albo ja czegoś nie rozumiem.

5

toolchain to zbiorcza nazwa na aplikacje, które służą do tworzenia aplikacji - imo transpiler do tej definicji pasuje :-)

0

Czyli jak dobrze rozumiem jakieś wbudowane narzędzie w Reacie transpiluje kod z Reacta na javascript?

2
sajek587 napisał(a):

Czyli jak dobrze rozumiem jakieś wbudowane narzędzie w Reacie transpiluje kod z Reacta na javascript?

"React" sam w sobie to po prostu biblioteka w JavaScript, tylko że napisana we względnie nowej wersji JavaScript - na tyle nowej że niektóre przeglądarki nie potrafią jeszcze uruchomić takiej aplikacji.

Oprócz tego, są w jego "ekosystemie" gotowe narzędzia które potrafią transpilować aplikacje napisane w Reacie na starsze wersje JavaScript, tak żeby np mogły być uruchomione w przeglądarce. Jednym z nich jest Babel.

sajek587 napisał(a):

Zakładając, że pisze np aplikację w React w Visual Studio Code. Visual Studio Code ma wbudowany kompilator, więc kompiluje kod, a następnie odpalam aplikację w przeglądarce przy użyciu komendy npm start.

Po pierwsze, ustalmy co siedzi u Ciebie w npm start - możesz podglądnąć plik package.json i zobaczyć co wykonuje Twoja komenda yarn start. Popularne opcje to np webpack serve (i wtedy aplikacja jest budowana z webpackiem), może się tam znaleźć vite (jeśli aplikacja jest nastawiona bardziej nad TypeScript, wtedy toolchainem jest vite, zamiast webpack), może się znaleźć też taki toolchain jak react-scripts, co w sumie jest takim "początkowym" narzędziem, które nie za bardzo się dobrze skaluje.

0

Czyli w sumie tworząc aplikację Reactową i odpalając aplikację komendą npm start kod aplikacji dopiero jest kompilowany w silniku Javascript w przeglądarce?

0
sajek587 napisał(a):

Czyli w sumie tworząc aplikację Reactową i odpalając aplikację komendą npm start kod aplikacji dopiero jest kompilowany w silniku Javascript w przeglądarce?

Podsumowując:

  • kod w React nie jest napisany w czystym JS, wymaga transpilacji
  • kod w JS jest kompilowany w chwili uruchomienia przez przeglądarkę tzw. just-in-time compilation
0
sajek587 napisał(a):

Czyli w sumie tworząc aplikację Reactową i odpalając aplikację komendą npm start kod aplikacji dopiero jest kompilowany w silniku Javascript w przeglądarce?

Pokaż co masz w skrypcie "start" w swoim pliku package.json.

Ale w skrócie:

  • Kod napisany przy użyciu biblioteki React jest napisany w najnowszym JS, i wymaga transpilacji
  • Już ztranspilowany kod jest po prostu uruchomiony i interpretowany przez przeglądarkę, JS'a raczej sie nie kompiluje - można dodać różne optymalizację podczas uruchomienia (jak np just-in-time compilation)
1
sajek587 napisał(a):

Powiedzcie mi czy dobrze to rozumiem:

Zakładając, że pisze np aplikację w React w Visual Studio Code. Visual Studio Code ma wbudowany kompilator, więc kompiluje kod, a następnie odpalam aplikację w przeglądarce przy użyciu komendy npm start.
Przeglądarka korzysta z jakiegoś silnika do JavaScript, więc tylko wykonuje już ten skompilowany kod czy na nowo kompiluje kod, a następnie go wykonuje?

Jak chcesz zrozumieć, to wywal Reacta i nie używaj gotowego npm start (domyślnie npm start nic nie robi).

Weź sobie postaw czysty projekt w JS:

mkdir foo
cd foo
npm init

i poczytaj o tym, jak postawić aplikację w JS używając np. Webpack, Babel (albo inne np. Esbuild, TypeScript itp.). Jak to skonfigurować. Do czego w zasadzie te narzędzia służą.

Riddle napisał(a):

"React" sam w sobie to po prostu biblioteka w JavaScript, tylko że napisana we względnie nowej wersji JavaScript - na tyle nowej że niektóre przeglądarki nie potrafią jeszcze uruchomić takiej aplikacji.

Przecież nie o to chodzi. React wymaga transpilacji, bo typowa apka reactowa korzysta z JSX, które do JS nie należy. Nowa wersja JS w przeglądarce nie pomoże, bo JSX to oddzielny format, a nie nowsza wersja JSa.

0
LukeJL napisał(a):
Riddle napisał(a):

"React" sam w sobie to po prostu biblioteka w JavaScript, tylko że napisana we względnie nowej wersji JavaScript - na tyle nowej że niektóre przeglądarki nie potrafią jeszcze uruchomić takiej aplikacji.

Przecież nie o to chodzi. React wymaga transpilacji, bo typowa apka reactowa korzysta z JSX, które do JS nie należy. Nowa wersja JS w przeglądarce nie pomoże, bo JSX to oddzielny format, a nie nowsza wersja JSa.

Tak, ale nie chodzi tylko o JSX, bo nawet jak stranspilujesz JSX do najnowszego JavaScript'a, to nadal to jest zbyt "nowe" dla niektórych przeglądarek, więc tak czy tak musisz go stranspilować do niższego JS'a (niektóre transpilery robią to za jednym obrotem).

Także, owszem - zarówno chodzi o JSX jak i o zbyt nową wersję JS'a.

0

Ja z tego co się orientuje jest tak JSX -> Javascript -> JIT do bytecode (w czasie pierwszego wywołania instrukcji, ona jest parsowana i wywoływana kompilacja do bytecode, bytecode wywołuje natywne funkcje w większości) -> JIT do opcode (tutaj już wszystkie pętle i inne operacje bytecodu i natywne funkcję razem optymalizowane i to nie jest wykonywane przez przeglądarkę, lecz czasem w niektórych przypadkach) -> JIT do hardware (tak istnieje coś takiego, ale nie jest to spotykane w przeglądarkach, ale już modele AI są możliwe do jitowania bezpośrednio do obwodów elektrycznych ) -> JIT do dowolnej logiki, (Teoretycznie istnieje jeszcze możliwość próby budowania na czymś innym niż tranzystory, np. korzystając z innych fizycznych własności, np. w DNA, czy spinach)

Z czego drugi JIT jest tylko w szczególnych przypadkach.
Tak pierwszy jest zrobiony po pierwszym przeanalizowaniu instrukcji, tak przy następnym razie już silnik nie musi od nowa parsować, tylko może bytecode'u użyć.

Inne języki jak python pozwalają od razu bytecode wygenerować, tak tutaj się jakoś przyjęło, że nie daje się bytecodu, gdyż każda przeglądarka może implementować dla swojego silnika inny bytecode, dlatego przesyła się w formie tekstowej.

0

tak tutaj się jakoś przyjęło, że nie daje się bytecodu, gdyż każda przeglądarka może implementować dla swojego silnika inny bytecode

JavaScript nie jest przesyłany w formie bajtkodu, bo w założeniu JS jest pisany przez ludzi, a ci średnio się odnajdują w hexedytorach :-P (dla odmiany WebAssembly jest transmitowany w formie binarnej)

1
CloudPro napisał(a):

Ja z tego co się orientuje jest tak JSX -> Javascript -> JIT do bytecode (w czasie pierwszego wywołania instrukcji, ona jest parsowana i wywoływana kompilacja do bytecode, bytecode wywołuje natywne funkcje w większości) -> JIT do opcode (tutaj już wszystkie pętle i inne operacje bytecodu i natywne funkcję razem optymalizowane i to nie jest wykonywane przez przeglądarkę, lecz czasem w niektórych przypadkach) -> JIT do hardware (tak istnieje coś takiego, ale nie jest to spotykane w przeglądarkach, ale już modele AI są możliwe do jitowania bezpośrednio do obwodów elektrycznych ) -> JIT do dowolnej logiki, (Teoretycznie istnieje jeszcze możliwość próby budowania na czymś innym niż tranzystory, np. korzystając z innych fizycznych własności, np. w DNA, czy spinach)

Z czego drugi JIT jest tylko w szczególnych przypadkach.
Tak pierwszy jest zrobiony po pierwszym przeanalizowaniu instrukcji, tak przy następnym razie już silnik nie musi od nowa parsować, tylko może bytecode'u użyć.

Inne języki jak python pozwalają od razu bytecode wygenerować, tak tutaj się jakoś przyjęło, że nie daje się bytecodu, gdyż każda przeglądarka może implementować dla swojego silnika inny bytecode, dlatego przesyła się w formie tekstowej.

Yyy... ale JIT to nie jest taki kompilator jak np kompilator w C albo w Javie.

JIT to jest po prostu optymalizacja runtime'u, to się tak nazywa "just in time compilation", ale to z kompilacją nie ma wiele wspólnego. To są po prostu optymalizacje wykonywane podczas działania aplikacji, stąd nazwa "just-in-time".

0

Pisząc o JIT w kontekście języków interpretowanych, zazwyczaj ma się na myśli kompilację bytecodu (stworzonego na podstawie AST) do kodu maszynowego w locie. Nie wszystkie instrukcje bytecodu są kompilowane w ten sposób bo nie zawsze jest to możliwe,np. przez zbyt dużą złożoność, więc niektóre instrukcje wysyłane są do uruchomienia za pomocą maszyny wirtualnej. Dlatego nie jest to standardowa kompilacja, tak jak wspomniał @Riddle.

0

Naszła mnie kolejna myśl. Skoro język JavaScript jest językiem interpretowanym to czemu używa just in time compilation? Języki interpretowane przecież nie są kompilowane.

0
sajek587 napisał(a):

Naszła mnie kolejna myśl. Skoro język JavaScript jest językiem interpretowanym to czemu używa just in time compilation? Języki interpretowane przecież nie są kompilowane.

Przecież pisaliśmy o tym wyżej, dla poprawy wydajności wykonania.

0

Ale czy w takim razie JavaScript jest językiem interpretowanym?

Edit: A ok. Przeczytałem jeszcze raz post Riddle i nieco więcej teraz zrozumiałem.

0
sajek587 napisał(a):

Ale czy w takim razie JavaScript jest językiem interpretowanym?

No tak. Za każdym razem jak przeglądarka ładuje stronę WWW, ładuje kod JS po czym uruchamia go za pomocą interpretera. JIT to tylko jeden z opcjonalnych metod przyspieszenia i optymalizacji tego procesu.

0

A czy just in time compilation w przypadku jsa kompiluje kod do kodu maszynowego czy tylko do kodu bajtowego? Jeśli tylko do kodu bajtowego to jak potem ten kod jest kompilowany do kodu maszynowego?

0
sajek587 napisał(a):

A czy just in time compilation w przypadku jsa kompiluje kod do kodu maszynowego czy tylko do kodu bajtowego? Jeśli tylko do kodu bajtowego to jak potem ten kod jest kompilowany do kodu maszynowego?

Pięć postów wyżej o tym pisałem. Jeśli chcesz wiedzieć jak konkretnie działa kompilacja bytecodu do machinecodu, to polecam to sobie wygooglać (np. sposób implementacji w V8 - silniku Chrome). Generalnie są określone konkretne operacje w bytecode które kompilator w locie "podmienia" na machinecode i uruchamia. Operacje bardziej złożone, np. wymagające dynamicznego rzutowania wartości do innego typu, wykonywane są już "na piechotę" przez VM.

1

Języki interpretowane przecież nie są kompilowane.

Pusty frazes. Co to są języki interpretowane? I czemu wg ciebie nie mogą być kompilowane? Bo gdzieś jakaś tam definicja podręcznikowa mówi?

Ale czy w takim razie JavaScript jest językiem interpretowanym?

w V8 z tego co wiem, zarówno istnieje kompilacja JIT do kodu natywnego, jak interpreter bajt kodu.
https://v8.dev/blog/ignition-interpreter
(ale to artykuł z 2016, nie zdziwiłbym się, gdyby od tego czasu już się tam pozmieniało. No i V8 to tylko jeden z kilku silników JSa, jakie są powszechnie używane)

sajek587 napisał(a):

Naszła mnie kolejna myśl. Skoro język JavaScript jest językiem interpretowanym to czemu używa just in time compilation?

Bo tak zdecydowali ludzie, którzy się tym zajmują. Widocznie mieli swoje powody. Jakie powody - mówią o tym w talkach na Youtube choćby.
Masz np. kanał Google Chrome Developers

Jak się robi coś tak ambitnego jak wirtualna maszyna języka programowania, która ma działać szybko i sprawnie, to nie zważa się na szkolne regułki.

2
sajek587 napisał(a):

A czy just in time compilation w przypadku jsa kompiluje kod do kodu maszynowego czy tylko do kodu bajtowego? Jeśli tylko do kodu bajtowego to jak potem ten kod jest kompilowany do kodu maszynowego?

Dobrze, to pozwól że podejde do tego od innej strony.

Sposób uruchamiania aplikacji napisany w różnych językach, zależy od jego przeznaczenia i dostępnych narzędzi (maszyny wirtualne, środowiska uruchomieniowe, wspierane platformy, etc.). Aplikacje napisane w jednych językach, są uruchamiane bezpośrednio w środowisku uruchomieniowym (np Python, JavaScript, Ruby, PHP), inne są najpierw kompilowane do kodu wspieranego przez ich maszyny wirtualne (Java, Clojure, podobne), a jeszcze inne są kompilowane bezpośrednio do kodu wspieranego bezpośrednio przez hardware (np C, C++, Objective C). Możliwe są też różne kombinacje między tymi podejściami, oraz możliwe są też dodatkowe optymalizacje.

Takie określenia/regułki jak "język interpretowany" albo "język kompilowany", to są uproszczenia, i w gruncie rzeczy nie mają żadnego znaczenia. To że można wrzucić Python w kategorię "język interpretowany", nie znaczy że nie może powstać coś takiego jak CPython.

Widzę że interesuje Cię tez temat JIT - więc jak już mówiłem, to jest bardzo modne słowo ostatnio, ale z kompilacją to ma niewiele wspólnego. Just in Time Compiler w wielu runtime'ach JS'a, to jest coś zupełnie innego niż np kompilator Javy albo kompilator C. To są zupełnie różne rzeczy i nie mają ze sobą nic wspólnego oprócz nazwy.

0
sajek587 napisał(a):

A czy just in time compilation w przypadku jsa kompiluje kod do kodu maszynowego czy tylko do kodu bajtowego? Jeśli tylko do kodu bajtowego to jak potem ten kod jest kompilowany do kodu maszynowego?

Normalnie musisz napisać kod, który wygeneruje kod, który potem skompilujesz i otrzymujesz binarkę lub po prostu dostajesz wskaźnik z adresem gdzie jest opcode wygenerowany.

Przykładowo w C to tworzysz kod i kompilujesz AOT:

printf("Dupa\n");

A dynamicznie to robisz tak, możesz zrobić AOT lub JIT kompilacje.

gcc_jit_param *param_format = gcc_jit_context_new_param(ctxt, NULL, const_char_ptr_type, "format");
gcc_jit_function *printf_func = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_INT), "printf", 1, &param_format, 1);
gcc_jit_rvalue *args[1];
args[0] = gcc_jit_context_new_string_literal(ctxt, "Dupa\n");
gcc_jit_block *block = gcc_jit_function_new_block(func, NULL);
gcc_jit_block_add_eval(block, NULL, gcc_jit_context_new_call(ctxt, NULL, printf_func, 1, args));
gcc_jit_block_end_with_void_return(block, NULL);

Najtrudniejsze to napisać reguły do generowania dynamicznie całego kodu, ale to akurat powinno być zaimplementowane w silniku.

W przypadku dynamicznych języków jak javascript nie wiesz jaki typ danych będzie przekazany do funkcji więc AoT kompilacja z góry odpada i dopiero po pierwszym uruchomieniu można wydedukować typy danych.
Jak masz typowany język lub hint typy to teoretycznie wygenerujesz AoT bez czekania na pierwsze uruchomienie danej funkcji.

0

javascript piszesz w plikach htm mozesz odpalic kllikajac plik htm a reszta zajmuje sie PRZEGLADARKA

0

Tak działa bajtkod w V8:
https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775
przy czym to tylko jeden element układanki.
Oni tam mają i interpreter bajtkodu i kompilator JIT i w ogóle manewrują między tymi i różnymi innymi modułami (Ignition, Crankshaft, Turbofan, Sparkplug i inne, o nazwach kojarzących się z silnikami). Przy czym jest to zmienne w czasie. Co kilka lat zmieniają architekturę tego V8 dodając/usuwając jakiś element o dziwnej nazwie.

Czyli jest to bardziej złożony problem, gdzie można mówić o ogólnych koncepcjach, ale co z tego, skoro na poziomie implementacji może to wyglądać nieco inaczej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1