# Pierwszy skrypt

Do umieszczenia skryptów na stronie służy znacznik `<script>`:

```xml
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    Odit quia aspernatur optio recusandae, atque, reiciendis
    tempore doloremque temporibus aliquid nemo vitae sint?

    <script>
        console.log("Nasz pierwszy skrypt!");
    </script>
</body>
</html>
```

### Umieszczanie skryptów w oddzielnym pliku <a href="#umieszczanie_skryptow_w_oddzielnym_pliku" id="umieszczanie_skryptow_w_oddzielnym_pliku"></a>

Skrypty możemy wstawiać na stronę na 2 sposoby:

* bezpośrednio w kodzie html (jak na powyższym przykładzie)
* w oddzielnych plikach .js

Wyobraź sobie, że tak jak w tym kursie chcesz za pomocą JavaScript obsłużyć menu strony.\
Gdybyś wstawiał ten skrypt w kod każdej podstrony z osobna, trochę by ci to zajęło.\
\
Gorzej, gdy za jakiś czas ktoś wyśle tobie maila, że masz w tym skrypcie literówkę. Musiałbyś na nowo przeglądać kod wszystkich podstron, poprawiać i dłubać. Da się? Da - tylko po co.\
\
Rozwiązaniem tego problemu jest **trzymanie skryptów w oddzielnych plikach .js**, a następnie dołączanie ich do strony (czyli podobnie jak w przypadku np. plików css).\
\
Gdy dołączasz skrypt z pliku, wszystko masz w jednym miejscu. Poprawiasz literówkę i poprawione będzie na każdej podstronie, na której ten plik jest dołączany.\
Co więcej, od razu wiadomo w jakim miejscu ten skrypt jest - co nie zawsze jest wiadome, gdy kawałki skryptów są rozrzucone po bardzo długich HTML.

Aby przyłączyć plik ze skryptami do naszej strony powinniśmy zastosować dodatkowy atrybut **src**. Cała treść skryptu powinna trafić do dołączanego pliku js:

```xml
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    Odit quia aspernatur optio recusandae, atque, reiciendis
    tempore doloremque temporibus aliquid nemo vitae sint?

    <script src="plik_ze_skryptem.js"></script>
</body>
</html>
```

## Która metoda jest lepsza? <a href="#ktora-lepsza" id="ktora-lepsza"></a>

W większości przypadków raczej ta z zewnętrznym plikiem. Tak robi większość stron.\
Ale nie jest to wcale 100% normą. Część stron, którym bardzo zależy na optymalizacji i liczy się tutaj każdy request () wstawia swoje całe skrypty i style inline w kod html strony. Dzięki temu przeglądarka nie musi dociągać dodatkowych plików.

Osobiście został bym przy skryptach w oddzielnych plikach. Ewentualnie szybkie, krótkie zadania gdzie skrypty to tylko kilka linii kodu spokojnie możemy pisać bezpośrednio w html.

### Gdzie wstawiać nasze skrypty <a href="#gdzie-wstawiac" id="gdzie-wstawiac"></a>

Skrypty możesz wrzucać w różne miejsca na stronie. Najczęściej spotykanymi miejscami są sekcja HEAD i koniec sekcji BODY:

```html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="modernizr.js"></script>
    </head>
    <body>
        ..treść strony...

        <script src="super-script.js"></script>
    </body>
</html>
```

Wybór miejsca wiąże się z dwiema kwestiami.\
Pierwsza z nich tyczy się zasady, która mówi o tym, by użytkownik dostawał w pierwszej chwili treść strony.\
Cała interakcja (JavaScript), graficzne dodatki itp. powinny być wysyłane w drugiej kolejności. Główna treść dokumentu nie powinna być blokowana przed jak najszybszym wyświetleniem, stąd koniec strony to dobry wybór na umieszczenie skryptów.

Druga sprawa tyczy się samych skryptów. Bardzo często będziesz chciał w nich działać na konkretnych elementach strony. Przykładowo zapragniesz pokazać przycisk, ukryć formularz, pokazać użytkownikowi jakieś okienko itp. Jeżeli twój skrypt zostanie wczytany przed takim elementem (czyli w kodzie HTML będzie się znajdował przed takim elementem HTML), a nie posiada żadnych metod do wykrywania czy cała strona została już wczytana, to dostaniesz błąd wynikający z tego, że skrypt ten nie widzi elementu, który zostanie wczytany dopiero po nim.

## Atrybuty async i defer <a href="#async-defer" id="async-defer"></a>

Do znacznika script możesz dodać dwa atrybuty: **async** lub **defer** (lub oba naraz):

```html
<script src="..." defer></script>
<script src="..." async></script>
<script src="..." async defer></script>
```

Przeglądarka czyta kod strony od góry do dołu. Gdy natrafi na dołączony skrypt, wstrzymuje ładowanie reszty strony aż do momentu całkowitego wczytania i wykonania skryptu.\
Przy malutkich skryptach nie ma to raczej znaczenia, ale przy większych skryptach może to powodować zauważalne blokowanie wczytywania strony.

Aby zapobiec takiemu blokowaniu stosuje się właśnie atrybuty defer lub async.

Atrybut `async` powoduje, że jeżeli przeglądarka czytając kod strony natrafi na plik ze skryptem zacznie go wczytywać w tle, równocześnie czytając dalszą część kodu strony. Jeżeli cały plik ze skryptem się wczyta, wtedy kod zostanie odpalony.

Atrybut `defer` działa w miarę podobnie. Plik ze skryptem też będzie wczytywany w tle. Różnica jest taka, że jeżeli przeglądarka wczyta już cały plik ze skryptem, odpali go po załadowaniu całego dokumentu (ale tuż przed odpaleniem zdarzenia DOMContentLoaded). Można to przyrównać do sytuacji, gdy dany skrypt byłby umieszczony tuż przed końcem body.

Różnica między tymi atrybutami jest też taka, że skrypty z atrybutem defer będą odpalane w kolejności w jakiej zostały wstawione do dokumentu. W przypadku async skrypty będą odpalane w kolejności "kto pierwszy ten lepszy", czyli który skrypt wczyta się wcześniej, ten zostanie wcześniej odpalony.

Niektóre starsze przeglądarki różnie [implementują te atrybuty.](https://stackoverflow.com/questions/10808109/script-tag-async-defer) Z tego też powodu [czasami spotkasz](https://github.com/h5bp/html5-boilerplate/blob/master/dist/index.html#L35) się ze znacznikami script, które nie tylko posiadają async i defer, ale też umieszczone są na końcu pliku. Są to skrypty, które nie mają istotnego znaczenia dla działania strony, więc nie muszą się szybko wczytywać.

**Gdzie więc umieszczać swoje skrypty?** W dzisiejszych czasach większość osób zaleca wstawianie skryptów do HEAD dokumentu (lub gdzieś na górę dokumentu) i dodawanie im atrybutu defer.

```html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Document</title>

        <script src="super-script.js" defer></script>
    </head>
    <body>
        ..treść strony...
    </body>
</html>
```

Dzięki temu przeglądarka będzie mogła wcześniej zacząć wczytywać twoje skrypty równocześnie czytając resztę strony.

I ja też zalecam takie podejście.

Niestety nawet tak prosta rzecz jak umieszczenie skryptu na stronie nie jest oczywista.\
Skrypt umieszczony wraz z atrybutem defer jest uruchamiany tuż przed wczytaniem drzewa DOM, ale też w niektórych przeglądarkach tuż przed przygotowaniem styli dla Javascript (tak zwany CSSOM). Dla użytkownika końcowego nie ma to totalnie znaczenia, natomiast zdarzają się sytuacje, gdy w naszych zaawansowanych skryptach chcemy np. pobrać zmienne z CSS. Gdy taki skrypt odpalimy z defer, w Chrome w pierwszej chwili nie będziemy w stanie takich zmiennych pobrać (a w zasadzie zwrócone zostaną puste wartości). W innych przeglądarkach o dziwo zadziała to poprawnie...\
Trochę więcej na ten temat [znajdziesz tutaj](https://stackoverflow.com/questions/42950574/are-deferred-scripts-executed-before-domcontentloaded-event).\
Czyli co? Nie używać? Używać jak najbardziej. A przy okazji testować.

Bardzo dobry artykuł na temat tych atrybutów znajdziesz pod adresem <http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html> oraz <https://addyosmani.com/blog/script-priorities/>

## Type module <a href="#module" id="module"></a>

Dołączając skrypty w HTML4, musieliśmy im ustawiać atrybut `type="text/javascript"`:

```js
<script src="super-script.js" type="text/javascript"></script>
```

W nowym HTML atrybut ten domyślnie ma taką wartość więc nie musimy go podawać.

Jeżeli zamiast tego podamy tutaj `type="module"`, skrypty będą traktowane jako oddzielne moduły. Więcej o samych modułach nauczymy się w innym rozdziale.

[Dodatkowych atrybutów](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#Attributes) jest jeszcze kilka, przy czym nie są już tak często stosowane.
