Opi käyttämään Resource Timing API:a frontend-suorituskyvyn diagnosointiin ja optimointiin. Mittaa jokaisen resurssin latausaika DNS-hauista sisällön lataukseen.
Frontend-suorituskyvyn salat: Syväsukellus Resource Timing API:hin
Verkkokehityksen maailmassa nopeus ei ole vain ominaisuus; se on positiivisen käyttäjäkokemuksen perusvaatimus. Hitaasti latautuva verkkosivusto voi johtaa korkeampiin poistumisprosentteihin, heikompaan käyttäjien sitoutumiseen ja lopulta negatiiviseen vaikutukseen liiketoiminnan tavoitteisiin. Vaikka työkalut, kuten Lighthouse ja WebPageTest, tarjoavat korvaamattomia korkean tason diagnooseja, ne edustavat usein yksittäistä, synteettistä testiä. Jotta voimme todella ymmärtää ja optimoida suorituskykyä globaalille yleisölle, meidän on mitattava todellisten käyttäjien kokemusta heidän laitteillaan ja verkoissaan. Tässä kohtaa kuvaan astuu todellisten käyttäjien monitorointi (Real User Monitoring, RUM), ja yksi sen tehokkaimmista työkaluista on Resource Timing API.
Tämä kattava opas vie sinut syväsukellukselle Resource Timing API:hin. Tutustumme siihen, mikä se on, kuinka sitä käytetään ja miten sen yksityiskohtainen data muutetaan käytännön toimenpiteiksi, jotka voivat parantaa sovelluksesi lataussuorituskykyä merkittävästi. Olitpa kokenut frontend-kehittäjä tai vasta aloittamassa suorituskyvyn optimointimatkaasi, tämä artikkeli antaa sinulle tiedot, joiden avulla voit analysoida ja ymmärtää sivusi jokaisen yksittäisen resurssin verkkosuorituskykyä.
Mikä on Resource Timing API?
Resource Timing API on selainpohjainen JavaScript API, joka tarjoaa yksityiskohtaista verkon ajoitusdataa jokaisesta resurssista, jonka verkkosivu lataa. Ajattele sitä mikroskooppisena linssinä sivusi verkkotoimintaan. Jokaiselle kuvalle, skriptille, tyylisivulle, fontille ja API-kutsulle ( `fetch` tai `XMLHttpRequest` kautta) tämä API tallentaa korkean resoluution aikaleiman verkkopyynnön jokaisesta vaiheesta.
Se on osa laajempaa suorituskyvyn API-perhettä, jotka yhdessä tarjoavat kokonaisvaltaisen kuvan sovelluksesi suorituskyvystä. Siinä missä Navigation Timing API keskittyy päädokumentin elinkaareen, Resource Timing API tarkentaa kaikkiin riippuvaisiin resursseihin, joita päädokumentti pyytää.
Miksi se on niin tärkeä?
- Yksityiskohtaisuus: Se menee yksittäistä "sivun latausaika" -mittaria pidemmälle. Näet tarkalleen, kuinka kauan DNS-haku, TCP-yhteys ja sisällön lataus kestivät tietylle kolmannen osapuolen skriptille tai kriittiselle hero-kuvalle.
- Todellisten käyttäjien data: Toisin kuin laboratoriossa käytettävät työkalut, tämä API suoritetaan käyttäjiesi selaimissa. Tämä mahdollistaa suorituskykydatan keräämisen monenlaisista verkko-olosuhteista, laitteista ja maantieteellisistä sijainneista, antaen sinulle todellisen kuvan globaalista käyttäjäkokemuksestasi.
- Käytännön oivallukset: Analysoimalla tätä dataa voit paikantaa tiettyjä pullonkauloja. Onko kolmannen osapuolen analytiikkaskriptin yhdistäminen hidasta? Suoriutuuko CDN-verkkosi heikosti tietyllä alueella? Ovatko kuvasi liian suuria? Resource Timing API tarjoaa todisteet, joita tarvitaan näihin kysymyksiin vastaamiseen luottavaisin mielin.
Resurssin latauksen anatomia: Aikajanan purkaminen
Resource Timing API:n ydin on `PerformanceResourceTiming`-objekti. Jokaista ladattua resurssia varten selain luo yhden tällaisen objektin, joka sisältää runsaasti ajoitus- ja kokotietoja. Näiden objektien ymmärtämiseksi on hyödyllistä visualisoida latausprosessi vesiputouskaaviona, jossa jokainen vaihe seuraa edellistä.
Käydään läpi `PerformanceResourceTiming`-objektin keskeiset ominaisuudet. Kaikki aika-arvot ovat korkean resoluution aikaleimoja, jotka mitataan millisekunteina sivun navigoinnin alusta (`performance.timeOrigin`).
startTime -> fetchStart -> domainLookupStart -> domainLookupEnd -> connectStart -> connectEnd -> requestStart -> responseStart -> responseEnd
Keskeiset ajoitusominaisuudet
name: Resurssin URL-osoite. Tämä on ensisijainen tunniste.entryType: Merkkijono, joka ilmaisee suorituskykymerkinnän tyypin. Meidän tarkoituksissamme tämä on aina "resource".initiatorType: Tämä on erittäin hyödyllinen vianetsinnässä. Se kertoo miten resurssia pyydettiin. Yleisiä arvoja ovat 'img', 'link' (CSS:lle), 'script', 'css' (CSS:n sisältä ladatuille resursseille kuten `@import`), 'fetch' ja 'xmlhttprequest'.duration: Resurssin kokonaisaika, laskettuna kaavallaresponseEnd - startTime. Tämä on yksittäisen resurssin päätason mittari.startTime: Aikaleima juuri ennen resurssin noudon alkamista.fetchStart: Aikaleima juuri ennen kuin selain aloittaa resurssin noutamisen. Se voi tarkistaa välimuistit (HTTP-välimuisti, Service Worker -välimuisti) ennen siirtymistä verkkoon. Jos resurssi tarjoillaan välimuistista, monet seuraavista ajoitusarvoista ovat nollia.domainLookupStart&domainLookupEnd: Nämä merkitsevät DNS-haun (Domain Name System) alkua ja loppua. Kesto (domainLookupEnd - domainLookupStart) on aika, joka kului verkkotunnuksen nimen muuntamiseen IP-osoitteeksi. Korkea arvo tässä voi viitata hitaaseen DNS-palveluntarjoajaan.connectStart&connectEnd: Nämä merkitsevät yhteyden muodostamisen alkuun ja loppuun palvelimelle. HTTP:lle tämä on TCP:n kolmitiekättely. Kesto (connectEnd - connectStart) on TCP-yhteyden muodostamisaika.secureConnectionStart: Jos resurssi ladataan HTTPS:n kautta, tämä aikaleima merkitsee SSL/TLS-kättelyn alkua. Kesto (connectEnd - secureConnectionStart) kertoo, kuinka kauan salausneuvottelu kesti. Hitaat TLS-kättelyt voivat olla merkki palvelimen virheellisestä konfiguraatiosta tai verkon viiveestä.requestStart: Aikaleima juuri ennen kuin selain lähettää varsinaisen HTTP-pyynnön resurssista palvelimelle. AikaconnectEnd:n jarequestStart:n välillä kutsutaan usein "pyyntöjen jonotusajaksi", jolloin selain odottaa vapaata yhteyttä.responseStart: Aikaleima, jolloin selain vastaanottaa vastauksen ensimmäisen tavun palvelimelta. Kesto (responseStart - requestStart) on kuuluisa Time to First Byte (TTFB). Korkea TTFB on lähes aina merkki hitaasta taustajärjestelmän prosessista tai palvelinpuolen viiveestä.responseEnd: Aikaleima, jolloin resurssin viimeinen tavu on vastaanotettu, mikä päättää pyynnön onnistuneesti. Kesto (responseEnd - responseStart) edustaa sisällön latausaikaa.
Resurssin koko-ominaisuudet
Resurssin koon ymmärtäminen on yhtä tärkeää kuin ajoituksen ymmärtäminen. API tarjoaa kolme keskeistä mittaria:
transferSize: Verkon yli siirretyn resurssin koko tavuina, mukaan lukien otsakkeet ja pakattu vastausrunko. Jos resurssi tarjoiltiin välimuistista, tämä on usein 0. Tämä luku vaikuttaa suoraan käyttäjän datapakettiin ja verkon käyttöaikaan.encodedBodySize: Hyötykuorman rungon koko tavuina *pakkauksen* (esim. Gzip tai Brotli) jälkeen mutta *ennen* purkamista. Tämä auttaa ymmärtämään itse hyötykuorman koon erillään otsakkeista.decodedBodySize: Hyötykuorman rungon koko tavuina sen pakkaamattomassa, alkuperäisessä muodossa. Vertaamalla tätäencodedBodySize-arvoon paljastuu pakkausstrategiasi tehokkuus. Jos nämä kaksi lukua ovat hyvin lähellä toisiaan tekstipohjaiselle resurssille (kuten JS, CSS tai HTML), pakkaus ei todennäköisesti toimi oikein.
Server Timing
Yksi tehokkaimmista integraatioista Resource Timing API:n kanssa on `serverTiming`-ominaisuus. Taustajärjestelmäsi voi lähettää suorituskykymittareita erityisessä HTTP-otsakkeessa (`Server-Timing`), ja nämä mittarit ilmestyvät vastaavan `PerformanceResourceTiming`-objektin `serverTiming`-taulukkoon. Tämä kuroo umpeen kuilun frontend- ja backend-suorituskyvyn valvonnan välillä, mahdollistaen tietokantakyselyiden aikojen tai API-käsittelyviiveiden näkemisen suoraan frontend-datassasi.
Esimerkiksi taustajärjestelmä voisi lähettää tämän otsakkeen:
Server-Timing: db;dur=53, api;dur=47.2, cache;desc="HIT"
Nämä tiedot olisivat saatavilla `serverTiming`-ominaisuudessa, mikä mahdollistaa korkean TTFB-arvon korreloimisen tietyn hitaan prosessin kanssa taustajärjestelmässä.
Miten Resource Timing -dataa käytetään JavaScriptillä
Nyt kun ymmärrämme saatavilla olevan datan, katsotaan käytännön tapoja kerätä sitä JavaScriptin avulla. Tähän on kaksi päämenetelmää.
Menetelmä 1: `performance.getEntriesByType('resource')`
Tämä on yksinkertaisin tapa aloittaa. Tämä metodi palauttaa taulukon kaikista `PerformanceResourceTiming`-objekteista niille resursseille, jotka ovat jo latautuneet valmiiksi sivulla kutsuhetkellä.
// Odota, että sivu latautuu varmistaaksesi, että useimmat resurssit on kaapattu
window.addEventListener('load', () => {
const resources = performance.getEntriesByType('resource');
resources.forEach((resource) => {
console.log(`Resurssi ladattu: ${resource.name}`);
console.log(` - Kokonaisaika: ${resource.duration.toFixed(2)}ms`);
console.log(` - Aloittaja: ${resource.initiatorType}`);
console.log(` - Siirtokoko: ${resource.transferSize} tavua`);
});
});
Rajoitus: Tämä menetelmä on tilannekuva tiettynä hetkenä. Jos kutsut sitä liian aikaisin, menetät resurssit, jotka eivät ole vielä latautuneet. Jos sovelluksesi lataa resursseja dynaamisesti kauan alkuperäisen sivunlatauksen jälkeen, sinun pitäisi kutsua tätä metodia toistuvasti, mikä on tehotonta.
Menetelmä 2: `PerformanceObserver` (Suositeltu tapa)
`PerformanceObserver` on modernimpi, vankempi ja suorituskykyisempi tapa kerätä suorituskykymerkintöjä. Sen sijaan, että sinä kyselisit dataa, selain työntää uusia merkintöjä observerisi callback-funktioon sitä mukaa, kun niitä tulee saataville.
Miksi se on parempi:
- Asynkroninen: Se ei tuki pääsäiettä.
- Kattava: Se voi kaapata merkintöjä heti sivun latauksen alusta alkaen, välttäen kilpailutilanteita, joissa skripti suoritetaan resurssin jo latauduttua.
- Tehokas: Se välttää tarpeen tehdä jatkuvia kyselyitä `setTimeout`:lla tai `setInterval`:lla.
Tässä on standardi toteutus:
try {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
// Käsittele jokainen resurssimerkintä sen saapuessa
if (entry.entryType === 'resource') {
console.log(`Resurssi havaittu: ${entry.name}`);
console.log(` - Aika ensimmäiseen tavuun (TTFB): ${(entry.responseStart - entry.requestStart).toFixed(2)}ms`);
}
});
});
// Aloita 'resource'-merkintöjen tarkkailu.
// 'buffered'-lippu varmistaa, että saamme merkinnät, jotka latautuivat ennen observerin luomista.
observer.observe({ type: 'resource', buffered: true });
// Voit lopettaa tarkkailun myöhemmin tarvittaessa
// observer.disconnect();
} catch (e) {
console.error('PerformanceObserver ei ole tuettu tässä selaimessa.');
}
buffered: true -vaihtoehto on kriittinen. Se käskee observeria lähettämään välittömästi kaikki `resource`-merkinnät, jotka ovat jo selaimen suorituskykymerkintöjen puskurissa, varmistaen, että saat täydellisen listan alusta alkaen.
Suorituskykypuskurin hallinta
Selaimilla on oletusraja sille, kuinka monta resurssien ajoitusmerkintää ne tallentavat (tyypillisesti 150). Hyvin monimutkaisilla sivuilla tämä puskuri voi täyttyä. Kun niin käy, selain laukaisee `resourcetimingbufferfull`-tapahtuman, eikä uusia merkintöjä enää lisätä.
Voit hallita tätä seuraavasti:
- Puskurin koon kasvattaminen: Käytä `performance.setResourceTimingBufferSize(limit)` asettaaksesi korkeamman rajan, esimerkiksi 300.
- Puskurin tyhjentäminen: Käytä `performance.clearResourceTimings()` käsiteltyäsi merkinnät tehdäkseen tilaa uusille.
performance.addEventListener('resourcetimingbufferfull', () => {
console.warn('Resurssien ajoituspuskuri on täynnä. Tyhjennetään...');
// Käsittele ensin olemassa olevat merkinnät observeristasi
// Tyhjennä sitten puskuri
performance.clearResourceTimings();
// Sinun saattaa olla tarpeen säätää puskurin kokoa uudelleen, jos tämä tapahtuu usein
// performance.setResourceTimingBufferSize(500);
});
Käytännön esimerkkejä ja toimenpiteitä
Datan kerääminen on vain ensimmäinen askel. Todellinen arvo piilee datan muuntamisessa käytännön parannuksiksi. Tarkastellaan joitakin yleisiä suorituskykyongelmia ja sitä, miten Resource Timing API auttaa ratkaisemaan ne.
Käyttötapaus 1: Hitaiden kolmannen osapuolen skriptien tunnistaminen
Ongelma: Kolmannen osapuolen skriptit analytiikkaan, mainontaan, asiakastuen widgetteihin ja A/B-testaukseen ovat tunnettuja suorituskyvyn heikentäjiä. Ne voivat latautua hitaasti, estää renderöintiä ja jopa aiheuttaa epävakautta.
Ratkaisu: Käytä Resource Timing API:a eristääksesi ja mitataksesi näiden skriptien vaikutuksen todellisiin käyttäjiisi.
const observer = new PerformanceObserver((list) => {
const thirdPartyScripts = list.getEntries().filter(entry =>
entry.initiatorType === 'script' &&
!entry.name.startsWith(window.location.origin)
);
thirdPartyScripts.forEach(script => {
if (script.duration > 200) { // Aseta kynnysarvo, esim. 200ms
console.warn(`Hidas kolmannen osapuolen skripti havaittu: ${script.name}`, {
duration: `${script.duration.toFixed(2)}ms`,
transferSize: `${script.transferSize} bytes`
});
// Todellisessa RUM-työkalussa lähettäisit nämä tiedot analytiikkapalvelimellesi.
}
});
});
observer.observe({ type: 'resource', buffered: true });
Käytännön toimenpiteet:
- Pitkä kesto: Jos skriptin kesto on jatkuvasti pitkä, harkitse, onko se todella tarpeellinen. Voidaanko sen toiminnallisuus korvata suorituskykyisemmällä vaihtoehdolla?
- Latausstrategia: Ladataanko skripti synkronisesti? Käytä `async`- tai `defer`-attribuutteja `<script>`-tagissa estääksesi sitä blokkaamasta sivun renderöintiä.
- Valikoiva lataus: Voidaanko skripti ladata ehdollisesti, vain niillä sivuilla, joilla sitä ehdottomasti tarvitaan?
Käyttötapaus 2: Kuvien toimittamisen optimointi
Ongelma: Suuret, optimoimattomat kuvat ovat yksi yleisimmistä syistä hitaisiin sivunlatauksiin, erityisesti mobiililaitteilla, joilla on rajallinen kaistanleveys.
Ratkaisu: Suodata resurssimerkinnät `initiatorType: 'img'` -tyypin mukaan ja analysoi niiden kokoa ja latausaikoja.
// ... PerformanceObserver-callbackin sisällä ...
list.getEntries()
.filter(entry => entry.initiatorType === 'img')
.forEach(image => {
const downloadTime = image.responseEnd - image.responseStart;
// Suurella kuvalla voi olla pitkä latausaika ja suuri transferSize
if (downloadTime > 500 || image.transferSize > 100000) { // 500ms tai 100KB
console.log(`Mahdollinen ongelma suuren kuvan kanssa: ${image.name}`, {
downloadTime: `${downloadTime.toFixed(2)}ms`,
transferSize: `${(image.transferSize / 1024).toFixed(2)} KB`
});
}
});
Käytännön toimenpiteet:
- Korkea `transferSize` ja `downloadTime`: Tämä on selvä merkki siitä, että kuva on liian suuri. Optimoi se käyttämällä moderneja formaatteja, kuten WebP tai AVIF, pakkaamalla se asianmukaisesti ja muuttamalla sen kokoa näyttömittojen mukaan.
- Käytä `srcset`: Toteuta responsiiviset kuvat käyttämällä `srcset`-attribuuttia tarjotaksesi eri kokoisia kuvia käyttäjän näkymän perusteella.
- Laiska lataus (Lazy Loading): Käytä `loading="lazy"` kuville, jotka ovat näkymän alapuolella, siirtääksesi niiden lataamista, kunnes käyttäjä vierittää ne näkyviin.
Käyttötapaus 3: Verkon pullonkaulojen diagnosointi
Ongelma: Joskus ongelma ei ole itse resurssi, vaan verkkoreitti siihen. Hidas DNS, viiveelliset yhteydet tai ylikuormitetut palvelimet voivat kaikki heikentää suorituskykyä.
Ratkaisu: Pura `duration` osavaiheisiinsa paikantaaksesi viiveen lähteen.
function analyzeNetworkPhases(resource) {
const dnsTime = resource.domainLookupEnd - resource.domainLookupStart;
const tcpTime = resource.connectEnd - resource.connectStart;
const ttfb = resource.responseStart - resource.requestStart;
const downloadTime = resource.responseEnd - resource.responseStart;
console.log(`Analyysi kohteelle ${resource.name}`);
if (dnsTime > 50) console.warn(` - Korkea DNS-aika: ${dnsTime.toFixed(2)}ms`);
if (tcpTime > 100) console.warn(` - Korkea TCP-yhteysaika: ${tcpTime.toFixed(2)}ms`);
if (ttfb > 300) console.warn(` - Korkea TTFB (hidas palvelin): ${ttfb.toFixed(2)}ms`);
if (downloadTime > 500) console.warn(` - Hidas sisällön lataus: ${downloadTime.toFixed(2)}ms`);
}
// ... kutsu analyzeNetworkPhases(entry) observerisi sisällä ...
Käytännön toimenpiteet:
- Korkea DNS-aika: DNS-palveluntarjoajasi saattaa olla hidas. Harkitse vaihtamista nopeampaan globaaliin palveluntarjoajaan. Voit myös käyttää `` ratkaistaksesi kriittisten kolmannen osapuolen verkkotunnusten DNS-nimet etukäteen.
- Korkea TCP-aika: Tämä viittaa viiveeseen yhteyden muodostamisessa. Sisällönjakeluverkko (CDN) voi vähentää tätä tarjoamalla resursseja maantieteellisesti lähempänä käyttäjää olevasta sijainnista. Käyttämällä `` voit suorittaa sekä DNS-haun että TCP-kättelyn etukäteen.
- Korkea TTFB: Tämä viittaa hitaaseen taustajärjestelmään. Työskentele taustajärjestelmätiimisi kanssa optimoidaksesi tietokantakyselyitä, parantaaksesi palvelinpuolen välimuistia tai päivittääksesi palvelinlaitteistoa. `Server-Timing`-otsake on paras ystäväsi tässä.
- Korkea latausaika: Tämä on resurssin koon ja verkon kaistanleveyden funktio. Optimoi resurssi (pakkaa, pienennä) tai käytä CDN:ää parantaaksesi läpäisykykyä.
Rajoitukset ja huomioon otettavat seikat
Vaikka Resource Timing API on uskomattoman tehokas, sillä on joitakin tärkeitä rajoituksia, jotka on syytä tiedostaa.
Ristiinalkuperän resurssit ja `Timing-Allow-Origin`-otsake
Turvallisuussyistä selaimet rajoittavat ajoitustietojen saatavuutta resursseille, jotka ladataan eri alkuperästä (verkkotunnus, protokolla tai portti) kuin pääsivusi. Oletusarvoisesti ristiinalkuperän resurssille useimmat ajoitusominaisuudet, kuten `redirectStart`, `domainLookupStart`, `connectStart`, `requestStart`, `responseStart`, ja koko-ominaisuudet kuten `transferSize` ovat nollia.
Näiden tietojen paljastamiseksi resurssia isännöivän palvelimen on sisällytettävä `Timing-Allow-Origin` (TAO) HTTP-otsake. Esimerkiksi:
Timing-Allow-Origin: * (Sallii minkä tahansa alkuperän nähdä ajoitustiedot)
Timing-Allow-Origin: https://www.your-website.com (Sallii vain sinun verkkosivustosi)
Tämä on ratkaisevan tärkeää, kun työskentelet omien CDN-verkkojesi tai API-rajapintojesi kanssa eri aliverkkotunnuksissa. Varmista, että ne on määritetty lähettämään TAO-otsake, jotta saat täyden näkyvyyden suorituskykyyn.
Selaintuki
Resource Timing API, mukaan lukien `PerformanceObserver`, on laajalti tuettu kaikissa moderneissa selaimissa (Chrome, Firefox, Safari, Edge). Vanhemmissa selaimissa se ei kuitenkaan välttämättä ole saatavilla. Kääri koodisi aina `try...catch`-lohkoon tai tarkista `window.PerformanceObserver`:n olemassaolo ennen sen käyttöä virheiden välttämiseksi vanhoilla asiakasohjelmilla.
Yhteenveto: Datasta päätöksiin
Resource Timing API on olennainen työkalu modernin verkkokehittäjän työkalupakissa. Se avaa verkon vesiputouskaavion saloja tarjoamalla raakaa, yksityiskohtaista dataa, jonka avulla voidaan siirtyä epämääräisistä valituksista, kuten "sivusto on hidas", tarkkoihin, dataan perustuviin diagnooseihin, kuten "kolmannen osapuolen chat-widgetillämme on 400 ms:n TTFB Kaakkois-Aasian käyttäjille."
Hyödyntämällä `PerformanceObserver`:ia todellisen käyttäjädatan keräämiseen ja analysoimalla jokaisen resurssin koko elinkaaren, voit:
- Vaatia kolmansien osapuolten palveluntarjoajia vastuuseen suorituskyvystään.
- Varmistaa CDN- ja välimuististrategioidesi tehokkuuden maailmanlaajuisesti.
- Löytää ja korjata ylisuuret kuvat ja optimoimattomat resurssit.
- Yhdistää frontend-viiveet taustajärjestelmän käsittelyaikoihin.
Matka nopeampaan verkkoon on jatkuva. Aloita tänään. Avaa selaimesi kehittäjäkonsoli, suorita tämän artikkelin koodinpätkät omalla sivustollasi ja aloita tutkimaan rikasta suorituskykydataa, joka on odottanut sinua koko ajan. Mittaamalla sitä, millä on merkitystä, voit rakentaa nopeampia, kestävämpiä ja nautittavampia kokemuksia kaikille käyttäjillesi, missä päin maailmaa he ovatkin.