Kiedy należy używać wbudowanego, a kiedy zewnętrznego kodu JavaScript?

129

Chciałbym wiedzieć, kiedy powinienem dołączyć zewnętrzne skrypty lub napisać je w kodzie html, jeśli chodzi o wydajność i łatwość obsługi.

Jaka jest ogólna praktyka w tym zakresie?

Scenariusz w świecie rzeczywistym - mam kilka stron html, które wymagają weryfikacji formularza po stronie klienta. W tym celu używam wtyczki jQuery, którą umieszczam na wszystkich tych stronach. Ale pytanie brzmi, czy ja:

  • napisać fragmenty kodu, które konfigurują ten skrypt w tekście?
  • zawrzeć wszystkie bity w jednym pliku, który jest wspólny dla wszystkich tych stron HTML?
  • umieścić każdy bit w osobnym pliku zewnętrznym, po jednym dla każdej strony html?

Dzięki.

Dan Burzo
źródło

Odpowiedzi:

114

W momencie opublikowania tej odpowiedzi (2008) zasada była prosta: wszystkie skrypty powinny być zewnętrzne. Zarówno pod względem konserwacji, jak i wydajności.

(Dlaczego wydajność? Ponieważ jeśli kod jest oddzielny, przeglądarki mogą go łatwiej buforować).

JavaScript nie należy do kodu HTML, a jeśli zawiera znaki specjalne (takie jak <, >), stwarza nawet problemy.

W dzisiejszych czasach zmieniła się skalowalność sieci. Zmniejszenie liczby żądań stało się ważną kwestią ze względu na opóźnienia w wykonywaniu wielu żądań HTTP. To sprawia, że ​​odpowiedź jest bardziej złożona: w większości przypadków nadal zalecane jest posiadanie zewnętrznego JavaScript . Jednak w niektórych przypadkach, szczególnie bardzo małych fragmentów kodu, wstawianie ich do kodu HTML witryny ma sens.

Konrad Rudolph
źródło
6
@ Nick: większość problemów można przezwyciężyć. Lepiej jednak w ogóle ich nie generować.
Konrad Rudolph
17
Czasami uzyskujesz lepszą wydajność podczas inliningu. Spójrz na źródło google.com . Wiedzą, co robią.
callum
13
@callum Google ma inny przypadek użycia niż 99,999999% witryn internetowych. Oczywiście mierzą niezwykle dokładnie i nawet najmniejsza różnica ma znaczenie. Ale tylko dlatego, że odkryli, że w ich konkretnym przypadku zastosowania inlining działa lepiej (prawdopodobnie dlatego, że skrypt zmienia się bardzo często?), Nie oznacza, że ​​możemy wyprowadzić z tego ogólną zasadę, ani nawet, że powinniśmy zignorować „konwencjonalne” reguła (do eksternalizacji skryptów).
Konrad Rudolph
8
@KonradRudolph - Zgoda, żadna ogólna zasada nie powinna wynikać z podejścia Google. Mówię tylko, że to wskazówka, że ​​warto zakwestionować regułę w swojej odpowiedzi. W każdym razie uważam, że powodem, dla którego robi to Google, jest zmniejszenie liczby żądań HTTP, co może przynieść korzyści ponad 0,000001% witryn. Przepustowość rośnie, ale czasy podróży w obie strony pozostają takie same. Usunięcie całego szeregowego żądania HTTP jest czasami lepsze niż korzyść buforowania zewnętrznego JS. Oczywiście zależy od wielkości twojego JS.
callum
5
@callum Chociaż to prawda, kwestia buforowania nadal pozostaje i pozostaje ważna. Zmniejszenie liczby przelotów w obie strony jest ważne tylko wtedy, gdy odwiedzający nie wracają (a wtedy nie uzyskasz wystarczającej liczby odwiedzin na stronie, aby miało to znaczenie) lub jeśli zawartość zmienia się tak często, że buforowanie plików skryptów nie przynosi korzyści.
Konrad Rudolph
31

Łatwość utrzymania jest zdecydowanie powodem, aby trzymać je na zewnątrz, ale jeśli konfiguracja jest jednowierszowa (lub ogólnie krótsza niż obciążenie HTTP, które można uzyskać za uczynienie tych plików zewnętrznymi), z punktu widzenia wydajności lepiej jest trzymać je w linii. Zawsze pamiętaj, że każde żądanie HTTP generuje pewne obciążenie w zakresie czasu wykonania i ruchu.

Oczywiście to wszystko staje się nieistotne w momencie, gdy twój kod jest dłuższy niż kilka linii i nie jest tak naprawdę specyficzny dla jednej strony. W momencie, gdy chcesz móc ponownie użyć tego kodu, uczyń go zewnętrznym. Jeśli nie, spójrz na jego rozmiar i zdecyduj.

Horst Gutmann
źródło
5
To jedna z moich obaw. Posiadanie oddzielnego żądania HTTP dla kilku wierszy kodu wydaje się marnotrawstwem.
Dan Burzo
Czy możesz opublikować przykładową konfigurację swojego kodu? IMO, jeśli ma mniej niż 300 znaków i absolutnie dotyczy strony, wstaw ją.
Horst Gutmann,
To powinna być najlepsza odpowiedź imo
sgarcia.dev
@Dan pamiętaj, że oddzielne żądanie ma miejsce tylko za pierwszym razem. Jeśli spodziewasz się, że użytkownicy będą ładować stronę więcej niż raz, buforowana zewnętrzna (nawet dla kilku wierszy) jest wyraźnie szybsza niż oczekiwanie na bajty dla tych kilku wierszy w sieci podczas ładowania strony n = 2 +.
jinglesthula
@HorstGutmann Jak wygląda pomoc zewnętrzna w utrzymaniu pliku? Osobiście wolę zewnętrzne js, gdy tylko jest to możliwe, ale czy jest coś obiektywnego, co ułatwia utrzymanie?
jinglesthula
21

Eksternalizacja javascript jest jedną z reguł wydajności Yahoo: http://developer.yahoo.com/performance/rules.html#external

Chociaż twarda i szybka reguła, że ​​zawsze powinieneś udostępniać skrypty na zewnątrz, będzie ogólnie dobrym rozwiązaniem, w niektórych przypadkach możesz chcieć dodać niektóre skrypty i style. Powinieneś jednak wbudować tylko te rzeczy, o których wiesz, że poprawią wydajność (ponieważ to zmierzyłeś).

Joeri Sebrechts
źródło
1
Myślę, że Yahoo również zaleca dodanie całego skryptu JavaScript do jednego wywołania HTTP - nie oznacza to jednak, że wszystkie skrypty powinny znajdować się w tym samym pliku podczas opracowywania
Paul Shannon
Ponadto, jak wspomniano powyżej, HTTP / 2 zmienia również praktykę „1 wywołania”.
jinglesthula
21

Jeśli zależy Ci tylko na wydajności, większość porad w tym wątku jest błędna i staje się coraz bardziej błędna w erze SPA, gdzie możemy założyć, że strona bez kodu JS jest bezużyteczna. Spędziłem niezliczone godziny optymalizując czasy ładowania strony SPA i weryfikując te wyniki w różnych przeglądarkach. Ogólnie wzrost wydajności poprzez zmianę orkiestracji kodu HTML może być dość dramatyczny.

Aby uzyskać najlepszą wydajność, musisz myśleć o stronach jak o dwuetapowych rakietach. Te dwa etapy z grubsza odpowiadają fazom <head>i <body>, ale myśl o nich jako o <static>i <dynamic>. Część statyczna jest w zasadzie stałą struną, którą wpychasz w dół rury odpowiedzi tak szybko, jak to tylko możliwe. Może to być trochę trudne, jeśli używasz wielu programów pośredniczących, które ustawiają pliki cookie (należy je ustawić przed wysłaniem zawartości http), ale w zasadzie jest to po prostu opróżnienie buforu odpowiedzi, miejmy nadzieję, że przed wskoczeniem do jakiegoś kodu szablonu (brzytwa, php, etc) na serwerze. Może się to wydawać trudne, ale po prostu wyjaśniam to źle, ponieważ jest prawie trywialne. Jak można się domyślić, ta statyczna część powinna zawierać wszystkie elementy javascript wbudowane i zminimalizowane. Wyglądałoby to jakoś

<!DOCTYPE html>
     <html>
         <head>
             <script>/*...inlined jquery, angular, your code*/</script>
             <style>/* ditto css */</style>
         </head>
         <body>
             <!-- inline all your templates, if applicable -->
             <script type='template-mime' id='1'></script>
             <script type='template-mime' id='2'></script>
             <script type='template-mime' id='3'></script>

Ponieważ wysłanie tej części przez kabel nic Cię nie kosztuje, możesz spodziewać się, że klient zacznie to odbierać gdzieś około 5 ms + opóźnienie po połączeniu z serwerem. Zakładając, że serwer jest dość blisko, opóźnienie może wynosić od 20 ms do 60 ms. Przeglądarki zaczną przetwarzać tę sekcję, gdy tylko ją otrzymają, a czas przetwarzania zwykle zdominuje czas przesyłania 20-krotnie lub więcej, co jest teraz zamortyzowanym oknem na przetwarzanie części po stronie serwera <dynamic>.

Przetwarzanie inline jquery + signalr + angular + ng animate + ng touch + ng Routes + lodash zajmuje około 50 ms (chrome, reszta może być o 20% wolniejsza). To niesamowite samo w sobie. Większość aplikacji internetowych ma mniej kodu niż wszystkie te popularne biblioteki razem wzięte, ale powiedzmy, że masz tyle samo, więc wygralibyśmy opóźnienie + 100 ms przetwarzania na kliencie (ta wygrana pochodzi z drugiej części transferu). Zanim nadejdzie druga porcja, przetworzyliśmy cały kod js i szablony i możemy rozpocząć wykonywanie transformacji dom.

Możesz sprzeciwić się temu, że ta metoda jest ortogonalna w stosunku do koncepcji wstawiania, ale tak nie jest. Jeśli zamiast wstawiać link do cdns lub własnych serwerów, przeglądarka musiałaby otworzyć inne połączenie (a) i opóźnić wykonanie. Ponieważ to wykonanie jest w zasadzie bezpłatne (ponieważ serwer rozmawia z bazą danych), musi być jasne, że wszystkie te skoki będą kosztować więcej niż ich całkowity brak. Gdyby istniało dziwactwo przeglądarki, które mówi, że zewnętrzny js wykonuje się szybciej, moglibyśmy zmierzyć, który czynnik dominuje. Moje pomiary wskazują, że dodatkowe żądania obniżają wydajność na tym etapie.

Dużo pracuję nad optymalizacją aplikacji SPA. Ludzie często myślą, że ilość danych to wielka sprawa, podczas gdy w rzeczywistości często dominują opóźnienia i wykonanie. Zminifikowane biblioteki, które wymieniłem, dodają do 300 kb danych, a to tylko 68 kb zgzip lub 200 ms do pobrania na telefonie 2 mbit 3g / 4g, co jest dokładnie takim opóźnieniem, jakie zajęłoby ten sam telefon, aby sprawdzić, czy ma te same dane w swojej pamięci podręcznej, nawet jeśli był buforowany przez proxy, ponieważ podatek od opóźnienia telefonu komórkowego (opóźnienie telefonu do wieży) nadal obowiązuje. Tymczasem połączenia z komputerami stacjonarnymi, które mają mniejsze opóźnienie pierwszego przeskoku, i tak zazwyczaj mają większą przepustowość.

Krótko mówiąc, teraz (2014) najlepiej jest wstawić wszystkie skrypty, style i szablony.

EDYCJA (MAJ 2016)

Ponieważ aplikacje JS stale się rozwijają, a niektóre z moich ładunków składają się teraz na ponad 3 megabajty zminimalizowanego kodu, staje się oczywiste, że przynajmniej popularne biblioteki nie powinny już być wbudowane.

Gleno
źródło
Nie dostałem, które jest teraz twoim zamortyzowanym oknem do przetwarzania po stronie serwera części <dynamic> - Serwer przetwarza wszystko, czego potrzebuje, a dopiero potem obsługuje cały wyrenderowany html (head + body), jakie inne przetwarzanie przez serwer jest potrzebny po tym?
BornToCode
@BornToCode Chodzi o to, aby dać klientowi coś do zrobienia w tym samym czasie, gdy strona serwera ma coś do zrobienia. Ponieważ biblioteki klienta wymagają interpretacji - lepiej jest rozpocząć ten proces przed wykonaniem jakichkolwiek obliczeń na serwerze. Zamortyzowane okno to czas potrzebny klientowi na przetworzenie JS. Okno to dostajesz za darmo, jeśli zaaranżujesz 2-stopniową rakietę.
Gleno
9

W rzeczywistości istnieje całkiem solidna podstawa do używania wbudowanego javascript. Jeśli js jest wystarczająco mały (jednolinijkowy), wolę javascript w tekście z dwóch powodów:

  • Lokalność . Nie ma potrzeby nawigowania po zewnętrznym pliku, aby sprawdzić zachowanie niektórych skryptów javascript
  • AJAX . Jeśli orzeźwiający jakiś fragment strony za pośrednictwem AJAX, to może stracić wszystkie swoje wozy DOM (onclick itp) do tej sekcji, w zależności od sposobu ich zbindowanych. Na przykład, używając jQuerymożesz użyć metod livelub delegate, aby to obejść, ale uważam, że jeśli js jest wystarczająco mały, lepiej jest po prostu wstawić go w tekście.
Miguel Ping
źródło
5

Innym powodem, dla którego zawsze powinieneś używać zewnętrznych skryptów, jest łatwiejsze przejście do polityki bezpieczeństwa treści (CSP) . CSP domyślnie zabrania wszystkich skryptów wbudowanych, dzięki czemu Twoja witryna jest bardziej odporna na ataki XSS.

chiborg
źródło
4

Spojrzałbym na wymagany kod i podzieliłbym go na tyle oddzielnych plików, ile potrzeba. Każdy plik js zawierałby tylko jeden „logiczny zestaw” funkcji itp. Np. jeden plik dla wszystkich funkcji związanych z logowaniem.

Następnie podczas tworzenia serwisu na każdej stronie HTML umieszczasz tylko te, które są potrzebne. Gdy zaczynasz korzystać ze swojej witryny, możesz ją zoptymalizować, łącząc każdy plik js potrzebny stronie w jeden plik.

Gen
źródło
4

Jedyną obroną, jaką mogę zaoferować dla wbudowanego javascipt, jest to, że używając silnie wpisanych widoków z .net MVC, możesz odwołać się do zmiennych c # w środku javascript, które uznałem za przydatne.

Austin_G
źródło
3

Trzy kwestie:

  • Ile kodu potrzebujesz (czasami biblioteki są konsumentami pierwszej klasy)?
  • Specyfika: czy ten kod działa tylko w kontekście tego konkretnego dokumentu lub elementu?
  • Każdy kod w dokumencie ma tendencję do wydłużania go, a tym samym wolniejszego. Poza tym względy SEO sprawiają, że jest oczywiste, że minimalizujesz wewnętrzne skrypty ...
roenving
źródło
2

Skrypty zewnętrzne są również łatwiejsze do debugowania za pomocą Firebug. Lubię testować jednostkowo mój JavaScript i mieć to wszystko z zewnątrz. Nienawidzę widzieć JavaScript w kodzie PHP, a HTML wygląda to na wielki bałagan.

Sprzęgło
źródło
2

Jeśli chodzi o utrzymywanie JavaScript na zewnątrz:

ASP.NET 3.5SP1 niedawno wprowadził funkcję tworzenia zasobu skryptu złożonego (scalanie kilku plików js w jeden). Inną korzyścią jest to, że gdy włączona jest kompresja serwera WWW, pobieranie jednego nieco większego pliku będzie miało lepszy współczynnik kompresji niż wiele mniejszych plików (również mniej narzutu http, transferu w obie strony itp.). Wydaje mi się, że zapisuje to przy początkowym ładowaniu strony, a następnie uruchamia się buforowanie przeglądarki, jak wspomniano powyżej.

Pomijając ASP.NET, ten screencast wyjaśnia korzyści bardziej szczegółowo: http://www.asp.net/learn/3.5-SP1/video-296.aspx

Brendan Kowitz
źródło
2

Inną ukrytą zaletą zewnętrznych skryptów jest to, że można je łatwo uruchomić za pomocą narzędzia do sprawdzania składni, takiego jak jslint . To może uchronić Cię przed wieloma rozdzierającymi serce, trudnymi do znalezienia błędami IE6.

Rozpoznać
źródło
1

W twoim scenariuszu brzmi to tak, jakby pisanie zewnętrznych rzeczy w jednym pliku współdzielonym między stronami byłoby dla ciebie dobre. Zgadzam się ze wszystkim, co zostało powiedziane powyżej.

mattlant
źródło
1

Podczas wczesnego tworzenia prototypów trzymaj kod w linii, aby uzyskać szybką iterację, ale upewnij się, że zanim dotrzesz do produkcji, wszystko będzie na zewnątrz.

Odważyłbym się nawet powiedzieć, że jeśli nie możesz umieścić całego kodu Javascript na zewnątrz, masz w rękach zły projekt i powinieneś refaktoryzować swoje dane i skrypty

Robert Gould
źródło
1

Google uwzględnił czasy wczytywania w pomiarach rankingu stron, jeśli często korzystasz z inline, zajmie to więcej czasu, zanim pająki zaindeksują twoją stronę, może to wpłynąć na ranking strony, jeśli musisz uwzględnić dużo. w każdym razie różne strategie mogą mieć wpływ na Twój ranking.

Kees Hessels
źródło
1

Cóż, myślę, że podczas tworzenia witryn zawierających jedną stronę należy używać wbudowanych, ponieważ skrypty nie będą musiały być udostępniane na wielu stronach

Zak Sheikh
źródło
0

Posiadanie wewnętrznych plusów JS: łatwiej jest zarządzać i debugować Możesz zobaczyć, co się dzieje

Wewnętrzne wady JS: ludzie mogą to zmienić, co naprawdę może cię denerwować.

zewnętrzne plusy JS: bez zmian możesz wyglądać bardziej profesjonalnie (a przynajmniej tak myślę)

zewnętrzne wady JS: trudniej zarządzać, trudno jest wiedzieć, co się dzieje.

TheComputerWizard
źródło
-3

Zawsze staraj się używać zewnętrznych js, ponieważ inline js jest zawsze trudny do utrzymania.

Co więcej, profesjonalnie wymagane jest używanie zewnętrznego js, ​​ponieważ większość programistów zaleca używanie js na zewnątrz.

Sam używam zewnętrznego js.

Daniel Puiu
źródło
2
Wymagane zawodowo? Czemu? Kto to mówi?
Siyah