Přejít k navigační liště

Zdroják » JavaScript » Zmenšujeme JavaScript

Zmenšujeme JavaScript

Články JavaScript, Různé

Rychlosti internetových přípojek stále rostou a na nějaký ten megabajt dnes už skoro nikdo nehledí (uživatelé mobilního připojení to mohou vidět jinak). Přesto není příliš přívětivé posílat návštěvníkům stránek velké obrázky nebo skripty o velikosti stovek kilobajtů. V článku si ukážeme, jak zmenšit skripty v JavaScriptu.

V programování se, stejně jako v životě, setkáme se spoustou protichůdných rad, jako je třeba známá dvojice přísloví „Mluviti stříbro, mlčeti zlato“ a „líná huba – holý neštěstí!“ Takovou programátorskou obdobu tvoří dvojice požadavků, kdy jeden říká, že by zdrojový kód programu měl být hojně dokumentovaný, aby se v něm vyznali i ostatní, a proti němu jde požadavek nezatěžovat přenosovou linku nefunkčními zbytečnostmi, přičemž právě dokumentační komentáře jsou z hlediska funkce programu zcela zbytné.

Tento paradox, ostatně jako spousta dalších, je jen zdánlivý. Důležité je aplikovat správné pravidlo ve správné situaci. Tedy: Když píšeme program, tak jej hojně komentujeme a odsazujeme a zpřehledňujeme, ale když jej posíláme na server nebo dokonce klientovi, tak z něj všechny „zbytečnosti“ (věci, které stroj stejně ignoruje) předem vypustíme tak, aby program fungoval stále stejně, ale byl menší. (Na webu, plném interpretovaných jazyků, paradoxně „menší“ znamená často i „rychlejší“.)

Zmenšit lze téměř vše, co se na běžné webové stránce vyskytuje – obrázky, skripty, styly i HTML kód. Zmenšené soubory lze navíc před posláním zkomprimovat např. pomocí gzip, pokud prohlížeč tuto techniku podporuje (většina ano). Ale o téhle metodě v článku řeč nebude. Řeč bude o nástrojích, které zmenší skripty pomocí ekvivalentních úprav – tedy takových, kdy je funkce zachována, ale výsledný kód je menší. Omezíme se na nástroje pro JavaScript, zmenšovače HTML a CSS necháme stranou, i když principiálně jsou metody podobné.

Jak zmenšit skript

První krok ke zmenšení jsme si už řekli: Vypusťte všechny komentáře. Ti nejpečlivější programátoři tak mohou ušetřit i přes 80 procent dat. Vypustíme všechny poznámky, všechny informace o verzi, všechny licenční informace (pokud to lze) – nebo myslíte, že do zdrojového kódu vašeho dynamického menu v JavaScriptu kouká někdo, kdo takové informace ocení?

Druhý krok ke zmenšení je rovněž jasný: Vyhoďte zbytečné mezery, odřádkování, tabelátory, zkrátka veškeré „bílé znaky“. Interpret je stejně přeskakuje, tak mu ušetřete práci (a než mě někdo chytí za slovo, tak dodám, že jsou jazyky, kde odsazení má svou syntaktickou roli, proto zdůrazňuji nadbytečné mezery).

Třetí krok: Zkraťte identifikátory. Z hlediska programátorského stylu je samosebou dobré, pokud se funkce jmenuje kontrolaHodnoty(), ale pokud je volána na patnácti místech (některé formuláře jsou už takové…), tak nám její přejmenování na k() ušetří skoro čtvrt kilobajtu. Přejmenujte proměnné na jednoznakové – ano, přesně tak, jak se to nemá dělat, když píšete kód.

Dovolte odbočku: V jisté firmě jsem narazil na interní pravidlo, které říkalo, že žádná proměnná se nesmí jmenovat i, j, q, abc0 nebo podobné nicneříkající jméno, a vedoucí programátor na tomto pravidle zcela rigidně lpěl, a ani konvenci „interní proměnné cyklu jsou i, j…“ neuznával, takže konstrukce for (var promennaCyklu=0; promennaCyklu<pocet; promennaCyklu++) byla zcela běžná. Pravidlo zvítězilo nad zdravým rozumem… Každopádně: Dovedete si představit úsporu přenášených dat zkrácením jmen proměnných v téhle firmě?

Čtvrtý krok ke zmenšení skriptů je: Napište to jinak, a kratší!

Vedlejším efektem většiny zkracovacích postupů je „znečitelnění“ zdrojového kódu. V hodně zmenšeném kódu už nikdo nic ručně neopraví a pravděpodobně z něj ani nevyčte – což sice přináší nutnost udržovat vedle sebe verze „rozbalené“ a „sbalené“, ale na druhou stranu se může „znečitelnění“ někdy hodit.

Problém těchto metod je, že jsou poněkud pracné na ruční provozování pokaždé, když změníme zdrojový kód. Proto vznikly „zkracovače kódu“, které výše uvedené kroky udělají automaticky za vás. Jsou dostupné v nejrůznějších podobách – od programů přes skripty v PHP, Pythonu atd. až po webové služby. Ukážeme si tři nejznámější nástroje pro zmenšení JavaScriptu: JSPacker, YUI Compressor a Closure Compiler, a lehce porovnáme jejich schopnosti.

JSPacker

Autorem JSPackeru je známý javascriptový programátor Dean Edwards. Jeho packer nabízí kromě základního zkrácení (vypuštěním komentářů a mezer) i zkrácení identifikátorů a cosi, co nazývá „Base62 encode“, při kterém je celý zdrojový text rozsekán na řetězce, opět složen a zprovozněn pomocí eval()  – takto upravené zdrojové kódy poznáte podle charakteristického „podpisu“: začínají textem eval(function(p,a,c,k,e,r). Pro porovnání jsem vybral zdrojový kód algoritmu SHA-256, který pochází z webu Webtoolkit. Velikost tohoto kódu v nezabalené podobě je 4182 byte. Porovnání jednotlivých metod komprese pak vypadá takto (první sloupec obsahuje název metody, druhý velikost výsledného souboru, třetí kompresní poměr:

JSPacker – porovnání výkonu kompresních metod
Prostá komprese 3073 0.735
Shrink variables 2802 0.67
Base62 3054 0.73
Base62 + Shrink 2962 0.708

Vidíte, že vypuštěním komentářů, vypuštěním mezer a přejmenováním proměnných a funkcí jsme ušetřili třetinu objemu. U takto malého souboru není úspora metodou Base62 vidět, ale např. u velkých knihoven (jQuery) je rozdíl velmi markantní (zmenšení na 0.8 se Shrink vs. zmenšení na 0.55 při použití Base62).

Packer je dostupný i jako aplikace v PHP, Perlu, .NETu a WSH: Packer download.

YUI Compressor

Yahoo nabízí v rámci svého open source projektu YUI (Yahoo User Interface) i kompresor, nazvaný prostě YUI Compressor. Na rozdíl od předchozího nástroje je YUI Compressor aplikace napsaná v Javě a volaná přes příkazový řádek (lze ji tedy použít a zakomponovat do deploy procesu a skripty zmenšovat transparentně až v okamžiku nasazení na server). Nabízí zhruba srovnatelné možnosti jako předchozí packer, výsledky má u velkých knihoven nepatrně horší, u testovací SHA-256 byl o několik bajtů lepši.

Google Closure Compiler

Poměrně novým nástrojem pro zmenšování zdrojových souborů v JavaScriptu je Google Closure Compiler, součást sady Closure Tools. Práce s ním je popsána poměrně podrobně v článku Compressing your JavaScript with Closure Compiler.

Samotný Compiler je open-source nástroj, který si můžete stáhnout. Google jej však nabízí i jako službu, a to jednak přes webové rozhraní, jednak přes RESTful API. Compiler nabízí tři úrovně komprese: První dvě odpovídají předchozím nástrojům (tedy vynechání mezer a komentářů, resp. totéž se zkrácením identifikátorů), třetí (Advanced) realizuje to, co jsme si v úvodu popsali jako bod 4: Přepracujte kód.

Ano, Closure Compiler vaše skripty přepíše: Vynechá nepoužité funkce, některé funkce převede na inline tvar, přejmenuje identifikátory, vyhodnotí zapsané konstantní výrazy, … Přepsáním kódu lze dosáhnout (podle Google) až dvoutřetinové úspory místa. Vedlejším efektem je kontrola správnosti kódu.

S testovacím souborem SHA-256 dosáhl Closure Compiler na úrovni Advanced velikosti 2182 bajtů, což představuje kompresní poměr 0.53.

Při testování pozor! Pokud budete kompilovat pouze soubor s knihovními funkcemi na Advanced, dostanete ultimátní kompresní poměr 0. Vysvětlení je jednoduché: Protože soubor obsahuje pouze funkce, které nejsou nikde volány, usoudí Compiler, že jsou zbytečné, a vyhodí je. Proto je potřeba funkce, které jsou volány odjinud, „exportovat“. Dokumentace doporučuje např. trik s přiřazením do objektu window: window['SHA256'] = SHA256;   čímž se funkce stane „použitou“, a Compiler ji nevyhodí.

Závěrem

Výše popsané metody zmenšování JavaScriptu nejsou rozhodně všechny, ale představují průřez těmi nejznámějšími. Z dalších nástrojů stojí za zmínku dva: Pravděpodobně prvním známějším JS packerem byl JSMIN Douglase Crockforda. Knihovna Dojo používá vlastní minifier s názvem Dojo ShrinkSafe. Srovnání těchto zmenšovačů, JSPackeru a YUI Compressoru nabízí web Javascript Compressor and Comparison Tool.

Samosebou lze výsledky takto zkrácených kódů gzipovat a ušetřit tak další kilobajty přenosového pásma.

Zdánlivě vypadá úspora pár kilobajtů jako nevýznamná; když si ji však vynásobíme počtem návštěvníků webu, objeví se rázem v jiném světle – ušetřených 100 kB se na větším webu celkem rychle promění v gigabajty (zbytečně) přenesených dat… Navíc s rozšiřováním mobilního webu, který je zatím leckdy pomalý a/nebo omezený FUP co do objemu přenesených dat, je úspora přenesených dat rozhodně zajímavá.

Komentáře

Subscribe
Upozornit na
guest
23 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Daniel Steigerwald

Jen bych doplnil pár informací z praxe.

JSPacker už dnes nikdo soudný nepoužívá. Dekomprese totiž probíhá v samotném Javascriptu, a pro takové Mootools, zabere klidně 300ms. Jediný důvod pro použití JSPackeru je situace, kdy není k dispozici GZIP (JSPacker má vysoký kompresní poměr), a v prohlížeči je nám ukradené, jak dlouho se kód rozbaluje. Nedovedu si takovou situaci představit ;)

Oproti tomu YUI Compressor ani Google Closure Compiler, žádnou vlastní kompresi (pomocí eval) neprovádí. Neexistuje tedy žádné zdržení při rozbalování. Dojo Shrinksafe snad ani nemá smysl zmiňovat, protože se dlouhodobě nevyvíjí.

YUI Compressor je nejlepší řešení pro ty, co chtějí kód bezpečně minimalizovat, a nechtějí u toho přemýšlet.

Google Closure Compiler je bomba. Takový kompresor sem si vždy přál =) Od YUI se liší možnostmi svého advanced módu. V článku se píše: „přejmenuje identifikátory“, což pro lokální proměnné YUI činí rovněž. Closure Compiler ale minimalizuje identifikátory všechny! Tedy i enumerace, jmenné prostory, klíče v objektech. Krom toho, že úspora je maximální, dostaneme dárkem i perfektní obfuskaci kódu.

Nástroj pro online porovnání účinnosti komprese.

Daniel Steigerwald

Jsi si jistý, že jsi tam ten link nedodal až po mém komentáři? (řekni prosím že jo) ;)

Michal Aichinger

Pro doplnění jeden kompresor z české dílny KJScompress

Michal Valoušek

Někdy se může hodit i opačný nástroj – převést „zkrácený“ a „obfuskovaný“ kód na něco stravitelnějšího: http://jsbeautifier.org/ (via http://simonwillison.net/)

Petr

Jsme na rootu, takže nepřekvapí že se „vypustil“ MS Ajax Minifier :-) Každopádně výsledky nemá špatné a pokud by to někoho zajímalo trochu do hloubky může kouknout na http://www.coderjournal.com/2010/01/performance-optimizations-made-by-microsoft-google-and-yahoo-javascript-minimizers/

Callo

Jak je to s výkonem. Je minimalizovaný kód i výkonnější nebo je to jedno? Víte někdo?

krocek

Compilery vetsinou maji funkci, ze ti odstrani komentare, mezery, nove radky a dalsi znaky ktere neovlivni tvuj kod, kvuli redukci velikosti souboru pro rychlejsi nacitani souboru, tak docela tezko.

Sadám husa

Jde o to jakým způsobem minimalizovaný, (z PHP) určitě bude rychlejší zpracování echo ‚Čao světe‘; než $pozdrav = ‚Čao‘; $world=‚světe‘; $text=$pozdrav.‘ ‚.$world; echo $text; – sic nepatrně ale skus si představit že takto máš napsaný každý znak v proměnné a pak do proměnných poskládáš slova z proměnných a pak větu… Tak to napsaný web by byl už výrazně pomalejší(nepatrně ale při kompletních stránkách z proměnných by byl výrazný) a při návštěvnosti 100 000 uživatelů denně by to bylo znatelné! Napříč tomu zkracovat strukturu asi nemá smysl, nemyslím si že by funkce psaná:
if
(podmínka)
{
blok…;
}
elseif
(podmínka)
{
blok…;
}
byla pomaleji zpracována jak u příkazu: if(podmínka){blok;}el­seif(podmínka){blok;} (mezera je stejně znak stejný jako konec řádku(v zpraco­vání))
To se bavím ale o scriptu zpracovávaným na straně vytíženého serveru, na straně klienta v případě javascriptu, ač nejsem odborník tak usuzuji že to nebude mít absolutně žádný význam až na scripty o 100000 řádcích+ A když tu napíšeš jakým způsobem(je jich mnoho!) chceš zkrátit kód, tak ti povím zda to má citelný smysl, nebo ne…

*

obfuskator

aprilchild

Byt muze zmenseni kodu prinest uzitek, v pripadech kdy lze, _vzdy_ pouzivejte komprimovani poskytovane webserverem (pripadne vlastni aplikaci). Samozrejme se spravnymi hlavickami pro rozumne cachovani, at to prohlizec za par hodin/dni nemusi stahovat ze serveru znovu. Rozdil „gzipnuty nezmenseny/ori­ginalni kod“ vs „gzipnuty a jeste zmenseny kod“ neni prilis znatelny, gzip je relativne ucinna komprese.

Existuje totiz jedna nevyhoda zmenseneho kodu – pri neodladenem skriptu se tezko trasuje pricina chyby. V pripade GCC je moznost vystopovani bugu jeste o rad ztizena (vznika jiny zdrojak).

Samozrejme lze namitnout, ze zmensujeme jen odladeny produkcni kod, ale kdo je bez chyb, ze.. Takhle to v praxi nemusi prilis fungovat (a nefunguje). U beta verzi (v dnesnim pojeti ala Google) ostrych aplikaci bych proto mozna (kvuli pripadnym chybam) zvolil spise gzip originalniho zdrojaku. Velikost nebude o mnoho vetsi nez komprimovana verze a nebudu ztracet cas s preklapenim cisel radku a nazvu identifikatoru, coz sice jde, ale jedna se o zbytecny „opruz“ (navic, pokud se minifikace vmestna na jeden radek (yui), hlaseni o chybe na radku 1 a sloupci 14562 nikoho prilis nepotesi).

Existuji samozrejme i jine duvody k minifikaci, nekdo muze trpet obsedantni touhou obfuskace a nechce puvodni zdrojak zobrazit vubec – taky duvod, byt spise filozofickeho nez technickeho razeni :).

František Kučera

Souhlas. On si stejně prohlížeč ten skript stáhne jen jednou a pak se serveru jen ptá, jestli se nezměnil – a ten mu většinou odpoví 304 Not Modified, takže kromě těch HTTP hlaviček se už nic nepřenáší. Z tohoto důvodu má smysl spíš než skripty nějak „komprimovat“, spojit je dohromady*, protože pak se prohlížeč dotazuje jen jednou a ty HTTP hlavičky s 304 tam proběhnou jen jednou a ne třeba pětkrát pro pět skriptů.

Co se týče „obfuskace“, jsem proti – IMHO na web patří otevřenost a taková tvůrčí spolupráce – inspirace**. Ale když se někdo úzkostně bojí, že by jeho úžasně kvalitní*** Javascript „ukradl“, tak ať, je to jeho věc.

*) když už člověk chce za každou cenu optimalizovat (často to ale bude předčasná optimalizace).

**) nemyslím tím nějaké sprosté kradení skriptů nebo designů, ale prostě inspiraci, vidím na webu nějaké zajímavé řešení, tak se podívám, jak uvnitř funguje a můžu si napsat podobný javascript… příště se třeba zase někdo inspiruje na mých stránkách. Ostatně různé „layouty“ nebo CSS triky mezi sebou webdesignéři taky sdílí.

***) „Na mém systému jsem pracoval již zhruba 10000 hodin. Při sazbě 1.500 Kč/hodinu, kterou si firemně účtuji…“ :-)

m.

Javascript je interpretovany jazyk, takze skor ako o zmensenie suboro kvoli prenosu zo servera ide o zmensenie suboru z dovodu rychlejsieho spracovavania interpreterom Javascriptu.

Daniel Steigerwald

Omyl, za a) se to týká jen IE < 9, za b) nedá se to ani změřit

_r3450n_

Ja sice z javou pracuju, ale do scriptovani moc nevidim.
Rozhodne chci ale autora pochvalit za ten obrazek :)
Sedi k tematu a pripomina mi pani fotografku :D

Martin

Trochu mě vytáčí, jak pořád všichni píší „tabelátor“ místo „tabulátor“. Je to odvozeno od slova tabulka. Když stiskneme tabulátor tak tím vytváříme tabulku. Žádnou tabelku čeština nezná.

OneHalf

Zaujima ma ako webdeveloperi v praxi riesia, ze na developer masine je vhodne mat plnu verziu JS suboru a na ostrom srv sa nasadi komprimovana. Hlavne teda v sucinnosti s verzovacim systemom. Pretoze ak mam na developer aj na ostrom srv tzv. working copy (bavme sa o SVN), tak mi hlava nebere ako tieto dve verzie pomocou verzovacieho systemu spravovat.

Idealne by bole, keby sa na ostrom srv okrem toho spojili vsetky JS/CSS do jedineho suboru pre minimalizaciu HTTP rqs.

Vdaka za akykolvek napad.

František Kučera

Dávat ty komprimované javascripty do SVN (nebo jiného verzovacího systému) je prasárna.

1) na kompresi bych se asi vykašlal, viz můj příspěvek výše. Pokud ale musí být:

2) dá se dělat nějakým skriptem – při nasazování nové verze spustíš skript, který ty JS zkomprimuje a nahraje na správné místo.

3) nebo by to šlo dělat „online“ – např. servlet, který si po nasazení aplikace načte ty JS to paměti, zkomprimuje nebo spojí do jednoho a pak je posílá klientům

kvr

Hm, buď viz níže, používat na ostrém serveru jiný zdroj (v závislosti třeba na konfiguraci se použije js_dev nebo js_mini).

Druhé řešení je náročnější, ale o řády lepší – v závislosti na uživatelských právech posílat buď původní nebo on-the-fly minifikovanou verzi, tak lze třeba i na ostrém serveru použít debug verzi pro vybrané uživatele (developery).

To druhé řešení používáme a pohodlí / ušetřený čas se nedá ocenit. Výše popsané je asi 1/10 věcí, mj. se js upravuje v rámci lokalizace, řeší drobné nekompatibility s IE (např. čárky za posledním prvkem pole či hash), dynamický class-loader atd.

Michal Aichinger

Pokud máte deployment řešet jinak než ručním kopírováním souborů přes ftp, tak skriptem všechny JS (případně i CSS) soubory concatnete a proženete KJSCompressem, jak jsem odkazoval výše. Na ostrém serveru musíte mít konfigurací zajištěno, že se budou vydávat tyto soubory a ne nekomprimované, tedy v šablonách bude nutná nějaká podmínka dle konfigurační direktivy.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.