Performans API'sine Giriş
Yayınlanan: 2022-08-10Performance API, canlı web uygulamanızın gerçek kullanıcı cihazlarında ve ağ bağlantılarında yanıt verme hızını ölçer. İstemci tarafı ve sunucu tarafı kodunuzdaki darboğazları aşağıdakilerle belirlemenize yardımcı olabilir:
- kullanıcı zamanlaması: İstemci tarafı JavaScript işlev performansının özel ölçümü
- boyama zamanlaması: Tarayıcı oluşturma metrikleri
- kaynak zamanlaması: Varlıkların ve Ajax çağrılarının yükleme performansı
- gezinme zamanlaması: Yönlendirmeler, DNS aramaları, DOM hazırlığı ve daha fazlasını içeren sayfa yükleme metrikleri
API, tipik performans değerlendirmesiyle ilgili çeşitli sorunları giderir:
- Geliştiriciler, uygulamaları genellikle hızlı bir ağa bağlı üst düzey bilgisayarlarda test eder. DevTools, daha yavaş cihazları taklit edebilir, ancak müşterilerin çoğu, havaalanı WiFi'sine bağlı iki yıllık bir mobil cihaz çalıştırdığında gerçek dünyadaki sorunları her zaman vurgulamaz.
- Google Analytics gibi üçüncü taraf seçenekleri genellikle engellenir ve bu da çarpık sonuçlara ve varsayımlara yol açar. Ayrıca bazı ülkelerde gizlilikle ilgili sorunlarla karşılaşabilirsiniz.
- Performance API, çeşitli ölçümleri
Date()
gibi yöntemlerden daha doğru bir şekilde ölçebilir.
Aşağıdaki bölümlerde, Performance API'yi kullanmanın yolları açıklanmaktadır. Biraz JavaScript bilgisi ve sayfa yükleme metrikleri önerilir.
Performans API'si Kullanılabilirliği
Çoğu modern tarayıcı, IE10 ve IE11 dahil olmak üzere Performans API'sini destekler (IE9'un bile sınırlı desteği vardır). API'nin varlığını aşağıdakileri kullanarak tespit edebilirsiniz:
if ('performance' in window) { // use Performance API }
API'yi tamamen Çoklu Doldurmak mümkün değildir, bu nedenle eksik tarayıcılar konusunda dikkatli olun. Kullanıcılarınızın %90'ı Internet Explorer 8 ile mutlu bir şekilde geziniyorsa, daha yetenekli uygulamalara sahip istemcilerin yalnızca %10'unu ölçmüş olursunuz.
API, tarayıcı işlemlerini durdurmadan bir arka plan iş parçacığında karmaşık hesaplamaları yürütmenin bir yolunu sağlayan Web Çalışanlarında kullanılabilir.
Çoğu API yöntemi, standart perf_hooks modülüyle sunucu tarafı Node.js'de kullanılabilir:
// Node.js performance import { performance } from 'node:perf_hooks'; // or in Common JS: const { performance } = require('node:perf_hooks'); console.log( performance.now() );
Deno, standart Performans API'sini sağlar:
// Deno performance console.log( performance.now() );
Yüksek çözünürlüklü zaman ölçümünü etkinleştirmek için komut dosyalarını --allow-hrtime
izniyle çalıştırmanız gerekir:
deno run --allow-hrtime index.js
Yüke, CPU'lara, RAM'e, sabit disklere ve bulut hizmeti sınırlarına bağlı olduğundan, sunucu tarafı performansının değerlendirilmesi ve yönetilmesi genellikle daha kolaydır. Donanım yükseltmeleri veya PM2, kümeleme ve Kubernetes gibi süreç yönetimi seçenekleri, kodu yeniden düzenlemeden daha etkili olabilir.
Aşağıdaki bölümler, bu nedenle istemci tarafı performansına odaklanmaktadır.
Özel Performans Ölçümü
Performans API'si, uygulama işlevlerinizin yürütme hızını zamanlamak için kullanılabilir. Date()
kullanarak zamanlama işlevlerini kullanmış veya karşılaşmış olabilirsiniz:
const timeStart = new Date(); runMyCode(); const timeTaken = new Date() - timeStart; console.log(`runMyCode() executed in ${ timeTaken }ms`);
Performans API'si iki temel avantaj sunar:
- Daha iyi doğruluk:
Date()
en yakın milisaniyeyi ölçer, ancak Performance API bir milisaniyenin kesirlerini ölçebilir (tarayıcıya bağlı olarak). - Daha iyi güvenilirlik: Kullanıcı veya işletim sistemi,
Date()
tabanlı ölçümlerin her zaman doğru olmaması için sistem saatini değiştirebilir. Bu, saatler ileri alındığında işlevlerinizin özellikle yavaş görünebileceği anlamına gelir!
Date()
eşdeğeri, belgeyi oluşturmaktan sorumlu süreç başladığında (sayfa yüklendiğinde) sıfıra ayarlanan yüksek çözünürlüklü bir zaman damgası döndüren performance.now()
'dur:
const timeStart = performance.now(); runMyCode(); const timeTaken = performance.now() - timeStart; console.log(`runMyCode() executed in ${ timeTaken }ms`);
Standart olmayan bir performance.timeOrigin
özelliği, IE ve Deno'da mevcut olmamasına rağmen, 1 Ocak 1970'ten bir zaman damgası da döndürebilir.
performance.now()
, birkaç ölçümden daha fazlasını yaparken pratik olmaz. Performans API'si, bir etiket adını performance.mark()
öğesine ileterek daha sonraki analiz için olayı kaydedebileceğiniz bir arabellek sağlar:
performance.mark('start:app'); performance.mark('start:init'); init(); // run initialization functions performance.mark('end:init'); performance.mark('start:funcX'); funcX(); // run another function performance.mark('end:funcX'); performance.mark('end:app');
Performans arabelleğindeki tüm işaret nesnelerinin bir dizisi aşağıdakiler kullanılarak çıkarılabilir:
const mark = performance.getEntriesByType('mark');
Örnek sonuç:
[ { detail: null duration: 0 entryType: "mark" name: "start:app" startTime: 1000 }, { detail: null duration: 0 entryType: "mark" name: "start:init" startTime: 1001 }, { detail: null duration: 0 entryType: "mark" name: "end:init" startTime: 1100 }, ... ]
performance.measure()
yöntemi, iki işaret arasındaki süreyi hesaplar ve ayrıca bunu Performans arabelleğinde saklar. Yeni bir hesaplama adı, başlangıç işareti adı (veya sayfa yükünden ölçmek için null) ve bitiş işareti adı (veya geçerli zamana ölçmek için null) iletirsiniz:
performance.measure('init', 'start:init', 'end:init');
Arabelleğe hesaplanan süre ile bir PerformanceMeasure nesnesi eklenir. Bu değeri elde etmek için, tüm ölçülerin bir dizisini talep edebilirsiniz:
const measure = performance.getEntriesByType('measure');
veya adına göre bir ölçü talep edin:
performance.getEntriesByName('init');
Örnek sonuç:
[ { detail: null duration: 99 entryType: "measure" name: "init" startTime: 1001 } ]
Performans Arabelleğini Kullanma
İşaretler ve ölçülerin yanı sıra Performans arabelleği, gezinme zamanlamasını, kaynak zamanlamasını ve boyama zamanlamasını (daha sonra tartışacağız) otomatik olarak kaydetmek için kullanılır. Tampondaki tüm girişlerin bir dizisini alabilirsiniz:
performance.getEntries();
Varsayılan olarak, çoğu tarayıcı 150'ye kadar kaynak ölçümü depolayan bir arabellek sağlar. Bu, çoğu değerlendirme için yeterli olacaktır, ancak gerekirse arabellek sınırını artırabilir veya azaltabilirsiniz:
// record 500 metrics performance.setResourceTimingBufferSize(500);
İşaretler ada göre temizlenebilir veya tüm işaretleri silmek için boş bir değer belirtebilirsiniz:
performance.clearMarks('start:init');
Benzer şekilde, ölçüler, tümünü temizlemek için ada veya boş bir değere göre temizlenebilir:
performance.clearMeasures();
Performans Arabelleği Güncellemelerini İzleme
PerformanceObserver , Performans arabelleğindeki değişiklikleri izleyebilir ve belirli olaylar meydana geldiğinde bir işlevi çalıştırabilir. DOM güncellemelerine yanıt vermek için MutationObserver'ı veya öğelerin görünüm alanına ne zaman kaydırıldığını algılamak için IntersectionObserver'ı kullandıysanız, sözdizimi tanıdık gelecektir.
İki parametreli bir gözlemci işlevi tanımlamanız gerekir:
- tespit edilen bir dizi gözlemci girişi ve
- gözlemci nesnesi Gerekirse, gözlemciyi durdurmak için
disconnect()
yöntemi çağrılabilir.
function performanceCallback(list, observer) { list.getEntries().forEach(entry => { console.log(`name : ${ entry.name }`); console.log(`type : ${ entry.type }`); console.log(`start : ${ entry.startTime }`); console.log(`duration: ${ entry.duration }`); }); }
İşlev, yeni bir PerformanceObserver nesnesine geçirilir. Gözlem observe()
bir dizi Performans arabelleği inputTypes dizisine iletilir:
let observer = new PerformanceObserver( performanceCallback ); observer.observe({ entryTypes: ['mark', 'measure'] });
Bu örnekte, yeni bir işaret veya ölçü eklemek, performanceCallback()
işlevini çalıştırır. Burada yalnızca mesajları günlüğe kaydederken, bir veri yüklemesini tetiklemek veya daha fazla hesaplama yapmak için kullanılabilir.
Boya Performansını Ölçme
Paint Timing API yalnızca istemci tarafı JavaScript'te mevcuttur ve Önemli Web Verileri için önemli olan iki ölçümü otomatik olarak kaydeder:
- first-paint: Tarayıcı sayfayı çizmeye başladı.
- first-contentful-paint: Tarayıcı, başlık veya resim gibi DOM içeriğinin ilk önemli öğesini boyamıştır.
Bunlar, Performans arabelleğinden bir diziye çıkarılabilir:
const paintTimes = performance.getEntriesByType('paint');
Sayfa tamamen yüklenmeden önce bunu çalıştırma konusunda dikkatli olun; değerler hazır olmayacaktır. Ya window.load
olayını bekleyin ya da paint
inputTypes'ı izlemek için bir PerformanceObserver
kullanın.
Örnek sonuç:
[ { "name": "first-paint", "entryType": "paint", "startTime": 812, "duration": 0 }, { "name": "first-contentful-paint", "entryType": "paint", "startTime": 856, "duration": 0 } ]
Yavaş bir ilk boyamaya genellikle oluşturmayı engelleyen CSS veya JavaScript neden olur. Tarayıcının büyük bir resim indirmesi veya karmaşık öğeler oluşturması gerekiyorsa, ilk içerikli boyama arasındaki boşluk büyük olabilir.
Kaynak Performans Ölçümü
Görüntüler, stil sayfaları ve JavaScript dosyaları gibi kaynaklar için ağ zamanlamaları otomatik olarak Performans arabelleğine kaydedilir. Ağ hızı sorunlarını çözmek için yapabileceğiniz çok az şey olsa da (dosya boyutlarını küçültmek dışında), daha büyük varlıklar, yavaş Ajax yanıtları veya kötü performans gösteren üçüncü taraf komut dosyalarıyla ilgili sorunları vurgulamaya yardımcı olabilir.
Bir dizi PerformanceResourceTiming ölçümü, aşağıdakiler kullanılarak arabellekten çıkarılabilir:
const resources = performance.getEntriesByType('resource');
Alternatif olarak, tam URL'sini ileterek bir varlığın metriklerini getirebilirsiniz:
const resource = performance.getEntriesByName('https://test.com/script.js');
Örnek sonuç:
[ { connectEnd: 195, connectStart: 195, decodedBodySize: 0, domainLookupEnd: 195, domainLookupStart: 195, duration: 2, encodedBodySize: 0, entryType: "resource", fetchStart: 195, initiatorType: "script", name: "https://test.com/script.js", nextHopProtocol: "h3", redirectEnd: 0, redirectStart: 0, requestStart: 195, responseEnd: 197, responseStart: 197, secureConnectionStart: 195, serverTiming: [], startTime: 195, transferSize: 0, workerStart: 195 } ]
Aşağıdaki özellikler incelenebilir:
- isim : Kaynak URL'si
- entryType : "kaynak"
- initiatorType : "komut dosyası" veya "bağlantı" gibi kaynağın nasıl başlatıldığı
- serverTiming : HTTP Server-Timing başlığında sunucu tarafından geçirilen
PerformanceServerTiming
nesneleri dizisi (sunucu tarafı uygulamanız daha fazla analiz için istemciye ölçümler gönderebilir) - startTime : Getirmenin başladığı zaman damgası
- nextHopProtocol : Kullanılan ağ protokolü
- workStart : Aşamalı Web Uygulaması Hizmet Çalışanı başlatmadan önce zaman damgası (istek bir Hizmet Çalışanı tarafından engellenmezse 0)
- redirectStart : Yönlendirme başladığında zaman damgası
- yönlendirmeEnd : Son yönlendirme yanıtının son baytından sonraki zaman damgası
- fetchStart : Kaynak getirilmeden önce zaman damgası
- domainLookupStart : DNS aramasından önce zaman damgası
- domainLookupEnd : DNS aramasından sonra zaman damgası
- connectStart : Bir sunucu bağlantısı kurmadan önce zaman damgası
- connectEnd : Bir sunucu bağlantısı kurduktan sonra zaman damgası
- SecureConnectionStart : SSL anlaşmasından önceki zaman damgası
- requestStart : Tarayıcının kaynağı istemesinden önceki zaman damgası
- answerStart : Tarayıcı ilk veri baytını aldığında zaman damgası
- answerEnd : Son baytı aldıktan veya bağlantıyı kapattıktan sonra zaman damgası
- süre : startTime ve responseEnd arasındaki fark
- transferSize : Başlık ve sıkıştırılmış gövde dahil olmak üzere bayt cinsinden kaynak boyutu
- encodingBodySize : Sıkıştırmayı açmadan önce bayt cinsinden kaynak gövdesi
- decodingBodySize : Sıkıştırmayı açtıktan sonra bayt cinsinden kaynak gövdesi
Bu örnek komut dosyası, Fetch API tarafından başlatılan tüm Ajax isteklerini alır ve toplam aktarım boyutunu ve süresini döndürür:
const fetchAll = performance.getEntriesByType('resource') .filter( r => r.initiatorType === 'fetch') .reduce( (sum, current) => { return { transferSize: sum.transferSize += current.transferSize, duration: sum.duration += current.duration } }, { transferSize: 0, duration: 0 } );
Navigasyon Performans Ölçümü
Önceki sayfanın kaldırılması ve mevcut sayfanın yüklenmesi için ağ zamanlamaları, tek bir PerformanceNavigationTiming
nesnesi olarak Performans arabelleğine otomatik olarak kaydedilir.
Aşağıdakileri kullanarak bir diziye çıkarın:
const pageTime = performance.getEntriesByType('navigation');
…veya sayfa URL'sini .getEntriesByName()
:
const pageTiming = performance.getEntriesByName(window.location);
Metrikler, kaynaklar için olanlarla aynıdır ancak aynı zamanda sayfaya özgü değerleri de içerir:
- entryType : Ör. "navigasyon"
- type : "Gezin", "yeniden yükle", "back_forward" veya "prerender"
- redirectCount : Yönlendirmelerin sayısı
- unloadEventStart : Önceki belgenin unload olayından önceki zaman damgası
- unloadEventEnd : Önceki belgenin boşaltma olayından sonraki zaman damgası
- domInteractive : Tarayıcı HTML'yi ayrıştırdığında ve DOM'u oluşturduğunda zaman damgası
- domContentLoadedEventStart : Belgenin DOMContentLoaded olayı tetiklenmeden önceki zaman damgası
- domContentLoadedEventEnd : Belgenin DOMContentLoaded olayı tamamlandıktan sonra zaman damgası
- domComplete : DOM yapımı ve DOMContentLoaded olayları tamamlandıktan sonra zaman damgası
- loadEventStart : Sayfa yükleme olayı tetiklenmeden önceki zaman damgası
- loadEventEnd : Sayfa yükleme olayından sonraki zaman damgası ve tüm varlıklar kullanılabilir
Tipik sorunlar şunları içerir:
- unloadEventEnd ve domInteractive arasında uzun bir gecikme. Bu, yavaş bir sunucu yanıtına işaret edebilir.
- domContentLoadedEventStart ve domComplete arasında uzun bir gecikme. Bu, sayfa başlatma komut dosyalarının çok yavaş olduğunu gösterebilir.
- domComplete ve loadEventEnd arasında uzun bir gecikme. Bu, sayfanın çok fazla öğeye sahip olduğunu veya birkaçının yüklenmesinin çok uzun sürdüğünü gösterebilir.
Performans Kaydı ve Analizi
Performance API, gerçek dünya kullanım verilerini derlemenize ve daha fazla analiz için bir sunucuya yüklemenize olanak tanır. Verileri depolamak için Google Analytics gibi bir üçüncü taraf hizmeti kullanabilirsiniz , ancak üçüncü taraf komut dosyasının engellenmesi veya yeni performans sorunlarına yol açması riski vardır. İzlemenin diğer işlevleri etkilememesini sağlamak için kendi çözümünüz gereksinimlerinize göre özelleştirilebilir.
Kullanıcıların eski tarayıcılarda olması, JavaScript'i engellemesi veya kurumsal bir proxy'nin arkasında olması nedeniyle istatistiklerin belirlenemediği durumlara karşı dikkatli olun. Hangi verilerin eksik olduğunu anlamak, eksik bilgilere dayanarak varsayımlarda bulunmaktan daha verimli olabilir.
İdeal olarak, analiz komut dosyalarınız, karmaşık hesaplamalar yaparak veya büyük miktarda veri yükleyerek performansı olumsuz etkilemez. Web çalışanlarından yararlanmayı ve eşzamanlı localStorage çağrılarının kullanımını en aza indirmeyi düşünün. Ham verileri daha sonra toplu olarak işlemek her zaman mümkündür.
Son olarak, çok hızlı veya çok yavaş aygıtlar ve istatistikleri olumsuz etkileyen bağlantılar gibi aykırı değerlere karşı dikkatli olun. Örneğin, dokuz kullanıcı bir sayfayı iki saniyede yükler ancak onuncu kullanıcı 60 saniyelik bir indirme yaşarsa, ortalama gecikme yaklaşık 8 saniyeye çıkar. Daha gerçekçi bir metrik, medyan rakam (2 saniye) veya 90. yüzdelik dilimdir (her 10 kullanıcıdan 9'u 2 saniye veya daha kısa bir yükleme süresi yaşar).
Özet
Web performansı geliştiriciler için kritik bir faktör olmaya devam ediyor. Kullanıcılar, sitelerin ve uygulamaların çoğu cihazda yanıt vermesini bekler. Arama Motoru Optimizasyonu, Google'da daha yavaş siteler eski sürüme geçirildiğinden de etkilenebilir.
Piyasada çok sayıda performans izleme aracı var, ancak çoğu sunucu tarafı yürütme hızlarını değerlendirir veya tarayıcı oluşturmayı değerlendirmek için sınırlı sayıda yetenekli istemci kullanır. Performans API'si, başka bir şekilde hesaplamanın mümkün olmayacağı gerçek kullanıcı metriklerini harmanlamak için bir yol sağlar.