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

Zdroják » JavaScript » Změřte rychlost vašeho webu, prohlížeče mají stopky

Změřte rychlost vašeho webu, prohlížeče mají stopky

Články JavaScript

Říkají vám něco Navigation Timing, High Resolution Time, Resource Timing a User Timing? Víte, co je to Performance Timeline a co měří First Paint? Dnešní článek vás uvede do celé sady „timing“ specifikací, které se v prohlížečích objevily v posledních letech.

Rychlé a responzivní webové stránky a aplikace znamenají spokojeného a neodcházejícího uživatele. Připomeňme si hodnoty, kde dochází ke změnám vnímání rychlosti odezvy. Pokud aplikace zareaguje na interakci s uživatelem do 200 ms, vnímá uživatel odezvu jako okamžitou, pokud do jedné sekundy, vnímá uživatel odezvu jako rychlou či respozivní, nad 3 sekundy už přesává být dojem reponzivní a nad 10 sekund už působí odezva jako neúnosně pomalá a uživatel odchází.

Abychom mohli udělat analýzu, jak se webová stránka chová v reálném světě s reálnými uživateli, potřebujeme tyto hodnoty měřit, což je důležité i proto, abychom se na optimalizace zaměřili na správných místech, kde budou mít největší efekt. V článku si představíme, jaké možnosti nám v tomto dávají javascriptová API prohlížečů. A tím nemyslíme jen profilování běhu javascriptu, který je málokdy tím slabým místem. Stejná API jsou užitečná také v situacích, kdy nemáme k dispozici vývojářské nástroje, např. v mobilu nebo tabletu.

Rychlost odezvy webové stránky je komplexní problém, který ovlivňuje latence a šířka pásma síťového připojení, výkonnost procesoru, množství dostupné paměti. Pro vykreslení stránky potřebujeme stáhnout kromě HTML dokumentu rovněž všechny resources (tj. styly, skripty, obrázky), zparsovat HTML a CSS, podle toho rozvrhnout, jak bude stránka vypadat a nakonec ji vykreslit (mezitím se vykonává javascriptový kód).

V roce 2010 vznikla pracovní skupina W3C Web Performance Working Group, ve které zasedli zástupci Google, Microsoftu, Mozilly, Intellu aj. Tato skupina se zaměřila výhradně na výkonnost webových stránek. Výsledkem jejich práce je například dnes již populární requestAnimationFrame nebo Page Visibility API, o kterém jsme na Zdrojáku již psali. Skupina však specifikovala mnohem více nových API, které si dále popíšeme.

Navigation Timing

Navigation Timing API umožňuje měřit skutečnost rychlost načtení stránky od události, která načtení vyvolala. Objekt window.performance.timing má vlastnosti, které ilustruje následující obrázek (převzat ze specifikace)

Některé události během načítání stránky si dovolíme více dovysvětlit a okomentovat:

  • navigationStart – čas události, která vyvolala načítání stránky
  • domLoading – začátek vytváření DOM
  • domInteractive – dokončeno parsování dokumentu do DOM (prohlížeč pokračuje exekucí script elemetů s atributem defer a async)
  • domContentLoadedEventStart – těsně před vyvoláním události DOMContentLoaded (všechny defer script elementy jsou již zpracovány)
  • domContentLoadedEventEnd – těsně po dokončení eventu DOMContentLoaded, zde dojde ke spuštění například jQuery ready handlerů
  • domComplete – všechny resources referencované z DOMu jsou načteny
  • loadEventStart – těsně před odpálením události load, dokončeno načtení stránky (včetně obrázků, iframů atd) i asynchronních resources JavaScriptem

Specifikace definuje dále objekt window.performance.navigation, který nese informaci o typu důvodu vyvolání načtení stránky. Jeho vlastnost type může nabývat hodnot:

  • TYPE_NAVIGATE – kliknutí na odkaz, zadání adresy, odeslání formuláře
  • TYPE_RELOAD – reload od uživatele či z JavaScriptu
  • TYPE_BACK_FORWARD – pohyb v historii
  • TYPE_RESERVED – ostatní

Dále vlastnost redirectCount říká, kolikrát během načítání došlo k redirectu.

Uveďme jednoduchý příklad, jak změřit, jak dlouho trvalo, než došlo k exekuci nějakého javascriptového kódu.

function onLoad() { 
	var now = new Date().getTime();
	var pageLoadTime = now - performance.timing.navigationStart;
	console.log("Načtení trvalo: " + pageLoadTime);
}

window.addEventListener('load', onLoad, false);

Navigation Timing z dnes probíraných API to mezi prohlížeči nejvíce rozšířené, konkrétně ho podporují Chrome 6+, Firefox 7+, IE 9+ a Opera 15+.

High Resolution Time

Specifikace High Resolution Time definuje typ DOMHighResTimeStamp, což je čas s přesností na tisíciny milisekund (při HW a SW omezeních však může být přesnost jen na milisekundy).

Funkce window.performance.now() vrací čas od události navigationStart právě jako typ DOMHighResTimeStamp, tedy s přesností na tisíciny milisekund.

Podpora v prohlížečích: Chrome 20+, Firefox 15+, IE 10+ a Opera 15+.

Resource Timing

Resource Timing API lze využít k měření rychlosti načítání jednotlivých resources stránky. Záznamy získáme jako pole pomocí window.performance.getEntriesByType("resource"). Každý prvek v poli je objekt rozhraní PerformanceResourceTiming, jehož vlastnosti popisuje následující obrázek (převzatý ze specifikace).

Všechny časy jsou typu DOMHighResTimeStamp. Objekt rozhraní PerformanceResourceTiming má navíc vlastnosti:

  • initiatorType s množinou hodnot „css“, „embed“, „img“, „link“, „object“, „script“, „subdocument“, „svg“, „xmlhttprequest“, „other“
  • name obsahuje URL
  • duration je rozdíl responseEnd − startTime

Z těchto dat můžete postavit waterfall, nebo si je posílat na server a statisticky zpracovávat tam, nebo nastavit horní limity a sledovat, zda a jak jsou překračovány.

Co všechno se dá z hodnot vyčíst? Například, že dojde načtení resource z lokální keše poznáme, pokud je splněna podmínka requestStart == fetchStart && requestStart == responseStart && reseponseStart != responseEnd. HTTP chybové stavy 4xx/5xx se dají rozpoznat, pokud jsou všechny hodnoty nula kromě startTime a fetchStart. Užitečná je například doba čekání ve frontě na stažení connectEnd == fetchStart ? requestStart - connectEnd : domainLookupStart - fetchStart (dle toho zda nemusí/musí navázat spojení).

Z důvodů bezpečnosti můžeme získat jenom omezené informace o resources z jiných domén – konkrétně jen startTime, fetchTime, duration a responseEnd. HTTP hlavička Timing-Allow-Origin umožňuje zpřístupnit tytu údaje i mimo doménu.

Podpora v prohlížečích: IE 10+, Chrome 25+, Opera 15+. Zajímavost je, že v IE jsou data dostupná již v průběhu načítání resource, v jiných prohlížečích až po skončení.

User Timing

User Timing API umožňuje měřit výkonnost vlastních javascriptových aplikací s přesností DOMHighResTimeStamp. Hodí se tedy například na profilování běhu. API zahrnuje dva koncepty – Mark a Measure, první implementuje rozhraní PerformanceMark a druhé implementuje PerformanceMeasure, obojí implementují PerformanceEntry (stejně jako dříve uvedené PerformanceResourceTiming).

  • performance.mark(markName) vytvoří značku s časovou hodnotou performance.now() (DOMHighResTimeStamp) pod zadaným jménem markName, které nemusí být unikátní
  • performance.measure(name, [startMark], [endMark]) změří délku časového intervalu, name nemusí být unikátní, startMark je značka pro začátek (navigationStart, pokud není uvedeno), endMark je značka pro konec (aktuální čas, pokud není uvedeno)

Příklad měření:

performance.mark("startTask1");
doTask1();
performance.mark("endTask1");

performance.mark("startTask2");
doTask2();
performance.mark("endTask2");

performance.measure('duration1', 'startTask1', 'endTask1');

performance.clearMarks();
performance.clearMeasures('duration1');

K naměřeným hodnotám se pak dostaneme pomocí performance.getEntriesByType("mark"), kdy získáme pole objektů s atributy name, entryType, startTime – časová hodnota typu DOMHighResTimeStamp a duration – vždy nula. Jednotlivé záznamy jsou seřazené podle startTime.

Hodnoty naměřených intervalů dostaneme pomocí performance.getEntriesByType("measure"). Každý objekt v poli má atributy name, entryType, startTime (DOMHighResTimeStamp) a duration (DOMHightResTimeStamp).

Nakonec performance.clearMarks([markname]) smaže všechny značky a performance.clearMeasures([measureName]) smaže intervaly.

Podpora v prohlížečích: IE 10+, Chrome 25+, Opera 15+.

Performance Timeline

Specifikace Performance Timeline popisuje rozhraní PerfromanceEntry a metody getEntries(), getEntriesByType(entryType) a getEntriesByName(name[, entryType]), které vrací PerformanceEntryList, což je objekt, který obsahuje pole PerformanceEntry objektů.

Skupina W3C Perfomance Working Group pracuje dále například na specifikacích:

  • Resource Priorities, díky které bude možné definovat priority resources například pomocí atributu lazyload
  • Beacon, která umožňuje asynchroně poslílat na server data (analytická data), aniž by blokovala uživatelovo vlákno (události vyvolané interakcí uživatele)
  • Navigation Error Logging, která umožňuje dozvědět se o chybě při navigaci mezi stránkami (500 http, tcp timeout, dns).
  • Resource Error Logging – to samé co předchozí pro resources

First Paint

Mimo standardizovaných API existují i ta nestandardizovaná. Kupříkladu v Chrome existuje alternativní timing object window.chrome.loadTimes()

{
	commitLoadTime: 1393428861.211465,
	connectionInfo: "http/1",
	finishDocumentLoadTime: 1393428861.979787,
	finishLoadTime: 1393428862.028446,
	firstPaintAfterLoadTime: 1393428862.144911,
	firstPaintTime: 1393428861.547534,
	navigationType: "Other",
	npnNegotiatedProtocol: "unknown",
	requestTime: 1393428860.658698,
	startLoadTime: 1393428860.730285,
	wasAlternateProtocolAvailable: false,
	wasFetchedViaSpdy: false,
	wasNpnNegotiated: false
}

Časy jsou narozdíl od předchozích v sekundách, nikoliv milisekundách. Zajimavá je hodnota firstPaintTime, což jak název vystihuje, je čas vykreslení prvního pixelu na obrazovku, tedy čas, kdy uživatel začne dostávat vizuální odezvu načítané stránky.

Jak jsou na tom ostatní prohlížeče ohledně této metriky? Internet Explorer od verze 9 disponuje touto hodnotu jako součást objektu NavigationTiming, konkrétně window.peformance.msFirstPaint.

V ostatních prohlížečích je třeba si vystačit s událostí load, která čeká na stažení všech CSS souborů a před tím, k žádnému kreslení na obrazovku dojít nemůže, takže se jedná o dolní odhad.

Demo

Ukázku použití najdete v přiloženém příkladu.

Komentáře

Subscribe
Upozornit na
guest
0 Komentářů
Inline Feedbacks
View all comments

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.