Zapytano mnie o to dzisiaj i nie byłem w stanie udzielić właściwej odpowiedzi.
Maszynopis transpiles do JS. Następnie jest trzęsienie drzewa, „mniej” (opcjonalnie) i co jeszcze w procesie wdrażania. Ale nic takiego (afaik) nie ma nic wspólnego z „kompilacją”. Wszystko jest pakowane i mocno optymalizowane, ale tak naprawdę nie jest kompilowane, prawda?
Istnieje nawet kompilator „wyprzedzający czas”, który naprawdę wykonuje zauważalną pracę. Za czym tęsknię
Sam JavaScript jest nadal interpretowany, prawda?
Odpowiedzi:
Zakładasz, że kompilacja oznacza pobranie kodu źródłowego i utworzenie kodu maszynowego, kodów niskiego poziomu itp. Jednak kompilowanie w rzeczywistości oznacza po prostu pobranie jednego kodu źródłowego i przekształcenie go w inny. Wydaje się więc rozsądne, aby powiedzieć, że wzięcie Typescript i utworzenie JavaScript jest formą kompilacji. Nie różni się od tego, co (na przykład) robi c #, gdy jest kompilowany do języka IL.
To powiedziawszy, powiedziałbym, że lepszym słowem na to jest Transpiling . Sugerowałbym, że kompilator Typescript jest lepiej opisany jako Transpiler.
Różnica jest subtelna i transpiler może być traktowany jako rodzaj kompilatora; ale (czysty) język skompilowany to (zwykle) zamiana języka wysokiego poziomu na język niższego (wyższego) poziomu (bliżej kodu maszynowego), jak przykład C #. Transpiler przekształca język wysokiego poziomu w język o podobnym poziomie (abstrakcji) (również wysoki poziom). *
Wynik skompilowanego kodu zazwyczaj nie jest językiem, który sam byś napisał . Wynikiem transpilera jest inny język wysokiego poziomu. Teoretycznie możesz napisać IL (jako przykład), ale tak naprawdę jest on zaprojektowany do tworzenia przez kompilator i nie ma żadnych narzędzi ani wsparcia do tego, tworzysz IL, kompilując tylko C # / vb.net. Podczas gdy JavaScript jest użytecznym (i używanym) językiem programowania sam w sobie.
* Wiele zastrzeżeń, ponieważ definicje tych słów i ich użycie są dość niejasne
źródło
Wydaje się, że zadajesz trzy pytania w jednym:
@ JörgWMittag udzielił bardzo dobrej odpowiedzi na to pytanie.
Zarówno TS, jak i Angular implementują prawdziwe kompilatory. Postępują zgodnie z tymi samymi etapami analizy leksykalnej, parsowania, analizy semantycznej i generowania kodu, co kompilatory C / C ++, które tworzą kod asemblerowy (z wyjątkiem prawdopodobnie optymalizacji). Jak widać, klasa / folder nosi nazwę „kompilator” zarówno w języku Angular, jak i TS .
Kompilator kątowy nie jest tak naprawdę powiązany z kompilatorem TypeScript. To są bardzo różne kompilatory.
Angular ma dwa kompilatory:
Zadaniem kompilatora widoku jest przekształcenie szablonu określonego dla szablonu komponentu w wewnętrzną reprezentację komponentu, który jest fabryką widoków, która jest następnie używana do tworzenia instancji widoku .
Oprócz przekształcania szablon, widok kompilator kompiluje także różne informacje metadanych w postaci takich jak dekoratorów
@HostBinding
,@ViewChild
etc.Załóżmy, że definiujesz komponent i jego szablon w następujący sposób:
@Component({ selector: 'a-comp', template: '<span>A Component</span>' }) class AComponent {}
Korzystając z tych danych, kompilator generuje następującą, nieco uproszczoną fabrykę komponentów:
function View_AComponent { return jit_viewDef1(0,[ elementDef2(0,null,null,1,'span',...), jit_textDef3(null,['My name is ',...]) ]
Opisuje strukturę widoku komponentu i jest używany podczas tworzenia wystąpienia komponentu. Pierwszy węzeł to definicja elementu, a drugi to definicja tekstu. Możesz zobaczyć, że każdy węzeł otrzymuje potrzebne informacje podczas tworzenia wystąpienia za pomocą listy parametrów. Zadaniem kompilatora jest rozwiązanie wszystkich wymaganych zależności i udostępnienie ich w czasie wykonywania.
Gorąco polecam przeczytanie tych artykułów:
Zobacz także odpowiedź na pytanie Jaka jest różnica między kompilatorem Angular AOT i JIT.
Zadaniem kompilatora modułów jest utworzenie fabryki modułów, która zasadniczo zawiera scalone definicje dostawców.
Aby uzyskać więcej informacji, przeczytaj:
źródło
Kompilacja oznacza przekształcenie programu napisanego w języku A w semantycznie równoważny program napisany w języku B taki, że ocena skompilowanego programu zgodnie z regułami języka B (na przykład interpretacja za pomocą interpretera dla B ) daje ten sam wynik i ma takie same skutki uboczne jak ocena oryginalnego programu zgodnie z regułami języka A (np. interpretacja z tłumaczem języka A ).
Kompilacja oznacza po prostu tłumaczenia program z języka A na język B . To wszystko, co to znaczy. (Należy również pamiętać, że jest całkowicie możliwe, że A i B są tym samym językiem).
W niektórych przypadkach mamy bardziej wyspecjalizowane nazwy dla niektórych typów kompilatorów, w zależności od tego, czym są A i B oraz co robi kompilator:
Zwróć także uwagę, że starsze źródła mogą używać terminów „tłumaczenie” i „tłumacz” zamiast „kompilacja” i „kompilator”. Na przykład C mówi o „jednostkach tłumaczeniowych”.
Możesz również natknąć się na termin „procesor języka”. Może to oznaczać kompilator, interpreter lub kompilatory i interpretery w zależności od definicji.
JavaScript to język. Języki to zbiór logicznych reguł i ograniczeń. Języki nie są interpretowane ani kompilowane. Języki po prostu są .
Kompilacja i interpretacja to cechy kompilatora lub interpretera (duh!). Każdy język można zaimplementować za pomocą kompilatora, a każdy język za pomocą interpretera. Wiele języków ma zarówno kompilatory, jak i tłumaczy. Wiele nowoczesnych wysokowydajnych silników wykonawczych ma co najmniej jeden kompilator i co najmniej jeden interpreter.
Te dwa terminy należą do różnych warstw abstrakcji. Gdyby angielski był językiem maszynowym, „interpreted-language” byłby błędem typu.
Zauważ również, że niektóre języki nie mają ani interpretera, ani kompilatora. Są języki, które nie mają żadnej implementacji. Mimo to są to języki i można w nich pisać programy. Po prostu nie możesz ich uruchomić.
Należy również pamiętać, że wszystko jest interpretowane w pewnym momencie : jeśli chcesz wykonać coś, to należy go interpretować. Kompilacja po prostu tłumaczy kod z jednego języka na inny. Nie działa. Prowadzi to interpretacja . (Czasami, gdy interpreter jest zaimplementowany sprzętowo, nazywamy go „procesorem”, ale nadal jest to interpreter).
Przykład: każda obecnie istniejąca implementacja głównego nurtu JavaScript ma kompilator.
V8 zaczynał jako czysty kompilator: kompilował JavaScript bezpośrednio do średnio zoptymalizowanego natywnego kodu maszynowego. Później dodano drugi kompilator. Teraz są dwa kompilatory: lekki kompilator, który tworzy umiarkowanie zoptymalizowany kod, ale sam kompilator jest bardzo szybki i zużywa mało pamięci RAM. Ten kompilator wstrzykuje również kod profilujący do skompilowanego kodu. Drugi kompilator to cięższy, wolniejszy i droższy kompilator, który jednak generuje znacznie ciaśniejszy, znacznie szybszy kod. Wykorzystuje również wyniki kodu profilującego wstrzykniętego przez pierwszy kompilator do podejmowania dynamicznych decyzji optymalizacyjnych. Ponadto decyzja, który kod należy ponownie skompilować za pomocą drugiego kompilatora, jest podejmowana na podstawie tych informacji o profilowaniu. Zwróć uwagę, że w żadnym momencie nie jest zaangażowany tłumacz. V8 nigdy nie interpretuje, zawsze się kompiluje. To nie robi nie zawierają nawet tłumacza. (Właściwie wydaje mi się, że obecnie tak jest, opisuję pierwsze dwie iteracje.)
SpiderMonkey kompiluje JavaScript do kodu bajtowego SpiderMonkey, który następnie interpretuje. Interpreter profiluje również kod, a następnie kod, który jest wykonywany najczęściej, jest kompilowany przez kompilator do natywnego kodu maszynowego. Tak więc SpiderMonkey zawiera dwa kompilatory: jeden z kodu bajtowego JavaScript do kodu bajtowego SpiderMonkey, a drugi od kodu bajtowego SpiderMonkey do natywnego kodu maszynowego.
Prawie wszystkie silniki wykonawcze JavaScript (z wyjątkiem V8) są zgodne z tym modelem kompilatora AOT, który kompiluje JavaScript do kodu bajtowego, oraz silnika trybu mieszanego, który przełącza się między interpretacją i kompilacją tego kodu bajtowego.
Napisałeś w komentarzu:
Co w ogóle oznacza „kod maszynowy”?
Jaki język maszynowy jednego człowieka jest językiem pośrednim drugiego człowieka i odwrotnie? Na przykład istnieją procesory, które mogą natywnie wykonywać kod bajtowy JVM, na takim procesorze kod bajtowy JVM jest rodzimym kodem maszynowym. Są też interpretery dla kodu maszynowego x86, kiedy ten kod maszynowy x86 jest interpretowany jako kod bajtowy.
Istnieje interpreter x86 o nazwie JPC napisany w Javie. Jeśli uruchomię kod maszynowy x86 na JPC działającym na natywnym procesorze JVM… który jest kodem bajtowym, a który natywnym? Jeśli skompiluję kod maszynowy x86 do JavaScript (tak, są narzędzia, które mogą to zrobić) i uruchomię go w przeglądarce na moim telefonie (który ma procesor ARM), który jest kodem bajtowym, a który natywnym kodem maszynowym? Co się stanie, jeśli kompilowany przeze mnie program jest emulatorem SPARC i używam go do uruchamiania kodu SPARC?
Zauważ, że każdy język wywołuje abstrakcyjną maszynę i jest językiem maszynowym dla tej maszyny. Tak więc każdy język (w tym języki bardzo wysokiego poziomu) jest rodzimym kodem maszynowym. Możesz również napisać tłumacza na każdy język. Tak więc każdy język (w tym kod maszynowy x86) nie jest rodzimy.
źródło
Uzyskanie napisanego kodu do uruchomienia w przeglądarce obejmuje dwie rzeczy:
1) Transpiling maszynopisu do JavaScript . To jest rodzaj rozwiązanego problemu. Myślę, że po prostu używają webpacka.
2) Kompilowanie abstrakcji kątowych w JavaScript . Mam na myśli takie rzeczy jak komponenty, rury, dyrektywy, szablony itp. To jest to, nad czym pracuje angular core team.
Jeśli naprawdę jesteś zainteresowany tym drugim bitem, kompilatorem kątowym, zobacz, jak autor kompilatora Tobias Bosch wyjaśnia kompilator Angular na AngularConnect 2016 .
Myślę, że między transpilacją a kompilacją dzieje się trochę zamieszania. To w pewnym sensie nie ma znaczenia i jest kwestią osobistego gustu, oba są po prostu przekształcane między reprezentacjami kodu. Ale definicja, której osobiście używam, jest taka, że transpilacja odbywa się między dwoma różnymi językami na podobnym poziomie abstrakcji (np. Maszynopis do javascript), podczas gdy kompilacja wymaga obniżenia poziomu abstrakcji. Myślę, że od szablonów, komponentów, potoków, dyrektyw itp. Do javascript jest krokiem w dół drabiny abstrakcji i dlatego nazywa się to kompilatorem.
źródło
Kompilator kątowy
Jedną z najważniejszych zmian z Angular 4 do 5 jest to, że kompilator został przepisany, aby był szybszy i dokładniejszy. W przeszłości aplikacje Angular korzystały z tego, co nazywamy kompilacją Just-in-Time (JIT), w której aplikacja była kompilowana w czasie wykonywania w przeglądarce przed uruchomieniem. Aktualizacje kompilatora w Angular 5 przyspieszyły przejście do AOT, co sprawiło, że aplikacja działała szybciej, ponieważ wykonuje mniej kompilacji podczas uruchamiania aplikacji. AOT stają się domyślnie włączone w każdej kompilacji produkcyjnej od wersji 1.5 interfejsu wiersza polecenia Angular.
Powiedzmy, że chcemy zbudować aplikację do wdrożenia i uruchomić następujące polecenie:
Dzieje się kilka rzeczy: wersja produkcyjna, minifikacja, zestawy zasobów, haszowanie nazw plików, potrząsanie drzewem, AOT ... (możemy to włączyć / wyłączyć za pomocą flag, np. Aot = false). Krótko mówiąc, flaga prod tworzy zoptymalizowany pakiet aplikacji, wykonując kompilację AOT przy użyciu ngc (kompilatora Angular), aby utworzyć zoptymalizowany kod gotowy dla przeglądarki ( tak, wstępnie kompiluje szablony ).
Kompilator języka TypeScript
Kompilator TypeScript, tsc , jest odpowiedzialny za kompilowanie plików TypeScript. To kompilator jest odpowiedzialny za implementację funkcji TypeScript, takich jak typy statyczne, a wynikiem jest czysty JavaScript, z którego zostały usunięte słowa kluczowe i wyrażenia TypeScript.
Kompilator TypeScript ma dwie główne cechy: jest to transpiler i narzędzie do sprawdzania typów. Kompilator transpiluje TypeScript do JavaScript. Wykonuje następujące transformacje kodu źródłowego:
Wywołując go, kompilator wyszukuje konfiguracje załadowane do tsconfig.json (szczegółową listę wszystkich opcji kompilatora wraz z wartościami domyślnymi można znaleźć tutaj ).
Pod wieloma względami kompilator TypeScript działa jak każdy inny kompilator. Ale jest jedna różnica, która może wyłapać nieostrożnych: domyślnie kompilator nadal emituje kod JavaScript, nawet jeśli napotka błąd. Na szczęście to zachowanie można wyłączyć, ustawiając ustawienie
noEmitOnError
konfiguracyjne na true w pliku tsconfig.json.Uwaga : tsc i ngc mają różne cele i nie chodzi o wybieranie jednego z nich. Ta odpowiedź może być interesująca .
Ta odpowiedź została stworzona na podstawie treści z następujących książek
Cloe, M. (2018). „Projekty Angular 5: Naucz się budować jednostronicowe aplikacje internetowe przy użyciu ponad 70 projektów”.
Dewey, B., Grossnicklaus, K., Japikse, P. (2017). „Tworzenie aplikacji internetowych w programie Visual Studio 2017: korzystanie z .NET Core i nowoczesnych struktur JavaScript”.
Freeman, A. (2019). „Essential TypeScript: od początkującego do profesjonalnego”.
Ghiya, P. (2018). „Mikrousługi TypeScript”.
Iskandar, A., Chivukulu, S. (2019). „Tworzenie stron internetowych za pomocą Angular i Bootstrap - wydanie trzecie”.
Hennessy, K., Arora, C. (2018). „Angular 6 by Example”.
Jansen, R., Wolf, I., Vane, V. (2016). „TypeScript: Modern JavaScript Development”.
Mohammed, Z. (2019). „Angular Projects”.
Seshadri, S. (2018). „Angular: działa i działa”.
Wilken, J. (2018). „Angular w akcji”.
źródło