Tìm hiểu kiến thức cơ bản về cách sử dụng API Điều hướng và API Thời gian tài nguyên để đánh giá hiệu suất tải trong thực tế.
Ngày phát hành: 8 tháng 10 năm 2021
Nếu đã sử dụng tính năng điều tiết kết nối trong bảng điều khiển mạng trong công cụ dành cho nhà phát triển của trình duyệt (hoặc Lighthouse trong Chrome) để đánh giá hiệu suất tải, thì bạn sẽ biết các công cụ đó tiện lợi như thế nào trong việc điều chỉnh hiệu suất. Bạn có thể nhanh chóng đo lường tác động của các hoạt động tối ưu hoá hiệu suất bằng tốc độ kết nối cơ sở nhất quán và ổn định. Vấn đề duy nhất là đây là kiểm thử tổng hợp để thu được dữ liệu phòng thí nghiệm chứ không phải dữ liệu thực địa.
Thử nghiệm tổng hợp không phải là không tốt, nhưng không thể hiện tốc độ tải trang web của bạn đối với người dùng thực. Điều đó yêu cầu dữ liệu trường mà bạn có thể thu thập từ các API Thời gian điều hướng và Thời gian tài nguyên.
API giúp bạn đánh giá hiệu suất tải trong thực tế
Navigation Timing (Thời gian điều hướng) và Resource Timing (Thời gian tài nguyên) là hai API tương tự nhau, có nhiều điểm trùng lặp đáng kể và đo lường hai điều khác biệt:
- Thời gian điều hướng đo tốc độ yêu cầu tài liệu HTML (tức là yêu cầu điều hướng).
- Điều tiết tài nguyên đo tốc độ của các yêu cầu đối với các tài nguyên phụ thuộc vào tài liệu, chẳng hạn như CSS, JavaScript, hình ảnh và các loại tài nguyên khác.
Các API này hiển thị dữ liệu của chúng trong một vùng đệm mục nhập hiệu suất. Bạn có thể truy cập vào vùng đệm này trong trình duyệt bằng JavaScript. Có nhiều cách để truy vấn vùng đệm hiệu suất, nhưng cách phổ biến là sử dụng performance.getEntriesByType
:
// Get Navigation Timing entries:
performance.getEntriesByType('navigation');
// Get Resource Timing entries:
performance.getEntriesByType('resource');
performance.getEntriesByType
chấp nhận một chuỗi mô tả loại mục nhập mà bạn muốn truy xuất từ vùng đệm mục nhập hiệu suất. 'navigation'
và 'resource'
truy xuất thời gian tương ứng cho các API Thời gian điều hướng và API Thời gian tài nguyên.
Lượng thông tin mà các API này cung cấp có thể rất lớn, nhưng đây là chìa khoá để bạn đo lường hiệu suất tải trong thực tế, vì bạn có thể thu thập các thời gian này từ người dùng khi họ truy cập vào trang web của bạn.
Vòng đời và thời gian của một yêu cầu mạng
Việc thu thập và phân tích thời gian điều hướng và tài nguyên cũng giống như khảo cổ học, vì bạn đang tái tạo cuộc sống ngắn ngủi của một yêu cầu mạng sau khi sự việc xảy ra. Đôi khi, việc hình dung các khái niệm sẽ giúp ích, và khi liên quan đến các yêu cầu mạng, công cụ dành cho nhà phát triển của trình duyệt có thể giúp ích.
Vòng đời của một yêu cầu mạng gồm các giai đoạn riêng biệt, chẳng hạn như quá trình tra cứu DNS, thiết lập kết nối, thương lượng TLS và các nguồn gây trễ khác. Những thời gian này được biểu thị dưới dạng DOMHighResTimestamp
. Tuỳ thuộc vào trình duyệt, độ chi tiết của thời gian có thể xuống đến micro giây hoặc được làm tròn lên đến mili giây. Bạn nên kiểm tra chi tiết các giai đoạn này và mối quan hệ giữa các giai đoạn này với Thời gian điều hướng và Thời gian tài nguyên.
tra cứu DNS
Khi người dùng truy cập vào một URL, Hệ thống tên miền (DNS) sẽ được truy vấn để chuyển đổi miền thành địa chỉ IP. Quá trình này có thể mất nhiều thời gian, thậm chí là thời gian bạn muốn đo lường trong thực tế. Navigation Timing (Thời gian điều hướng) và Resource Timing (Thời gian tài nguyên) hiển thị hai khoảng thời gian liên quan đến DNS:
domainLookupStart
là thời điểm bắt đầu tra cứu DNS.domainLookupEnd
là thời điểm kết thúc quá trình tra cứu DNS.
Bạn có thể tính tổng thời gian tra cứu DNS bằng cách trừ chỉ số bắt đầu khỏi chỉ số kết thúc:
// Measuring DNS lookup time
const [pageNav] = performance.getEntriesByType('navigation');
const totalLookupTime = pageNav.domainLookupEnd - pageNav.domainLookupStart;
Thương lượng kết nối
Một yếu tố khác ảnh hưởng đến hiệu suất tải là quá trình thương lượng kết nối, tức là độ trễ phát sinh khi kết nối với máy chủ web. Nếu có HTTPS, quá trình này cũng sẽ bao gồm thời gian đàm phán TLS. Giai đoạn kết nối bao gồm ba thời gian:
connectStart
là thời điểm trình duyệt bắt đầu mở kết nối với một máy chủ web.secureConnectionStart
đánh dấu thời điểm ứng dụng bắt đầu đàm phán TLS.connectEnd
là khi kết nối với máy chủ web đã được thiết lập.
Việc đo lường tổng thời gian kết nối cũng tương tự như đo lường tổng thời gian tra cứu DNS: bạn trừ thời gian bắt đầu khỏi thời gian kết thúc. Tuy nhiên, có một thuộc tính secureConnectionStart
bổ sung có thể là 0
nếu không sử dụng HTTPS hoặc nếu kết nối là liên tục. Nếu muốn đo lường thời gian đàm phán TLS, bạn cần lưu ý những điều sau:
// Quantifying total connection time
const [pageNav] = performance.getEntriesByType('navigation');
const connectionTime = pageNav.connectEnd - pageNav.connectStart;
let tlsTime = 0; // <-- Assume 0 to start with
// Was there TLS negotiation?
if (pageNav.secureConnectionStart > 0) {
// Awesome! Calculate it!
tlsTime = pageNav.connectEnd - pageNav.secureConnectionStart;
}
Sau khi quá trình tra cứu DNS và đàm phán kết nối kết thúc, thời gian liên quan đến việc tìm nạp tài liệu và các tài nguyên phụ thuộc của tài liệu sẽ bắt đầu.
Yêu cầu và phản hồi
Hiệu suất tải bị ảnh hưởng bởi hai loại yếu tố:
- Các yếu tố bên ngoài: Đây là những yếu tố như độ trễ và băng thông. Ngoài việc chọn một công ty lưu trữ và có thể là CDN, họ (hầu như) nằm ngoài tầm kiểm soát của chúng tôi, vì người dùng có thể truy cập web từ bất cứ đâu.
- Các yếu tố nội tại: Đây là những yếu tố như cấu trúc phía máy chủ và phía máy khách, cũng như kích thước tài nguyên và khả năng tối ưu hoá cho những yếu tố đó. Chúng ta có thể kiểm soát những yếu tố này.
Cả hai loại yếu tố này đều ảnh hưởng đến hiệu suất tải. Thời gian liên quan đến các yếu tố này rất quan trọng vì chúng mô tả thời gian tải tài nguyên xuống. Cả Thời gian điều hướng và Thời gian tài nguyên đều mô tả hiệu suất tải với các chỉ số sau:
fetchStart
đánh dấu thời điểm trình duyệt bắt đầu tìm nạp tài nguyên (Resource Timing) hoặc tài liệu cho một yêu cầu điều hướng (Navigation Timing). Yêu cầu này nằm trước yêu cầu thực tế và là thời điểm trình duyệt đang kiểm tra bộ nhớ đệm (ví dụ: HTTP và các thực thểCache
).workerStart
đánh dấu thời điểm một yêu cầu bắt đầu được xử lý trong trình xử lý sự kiệnfetch
của worker. Giá trị này sẽ là0
khi không có trình chạy dịch vụ nào kiểm soát trang hiện tại.requestStart
là thời điểm trình duyệt đưa ra yêu cầu.responseStart
là thời điểm byte đầu tiên của phản hồi đến.responseEnd
là thời điểm byte cuối cùng của phản hồi đến.
Các thời gian này cho phép bạn đo lường nhiều khía cạnh của hiệu suất tải, chẳng hạn như thời gian tìm nạp bộ nhớ đệm trong một worker dịch vụ và thời gian tải xuống:
// Cache seek plus response time of the current document
const [pageNav] = performance.getEntriesByType('navigation');
const fetchTime = pageNav.responseEnd - pageNav.fetchStart;
// Service worker time plus response time
let workerTime = 0;
if (pageNav.workerStart > 0) {
workerTime = pageNav.responseEnd - pageNav.workerStart;
}
Bạn cũng có thể đo lường các khía cạnh khác của độ trễ yêu cầu và phản hồi:
const [pageNav] = performance.getEntriesByType('navigation');
// Request time only (excluding redirects, DNS, and connection/TLS time)
const requestTime = pageNav.responseStart - pageNav.requestStart;
// Response time only (download)
const responseTime = pageNav.responseEnd - pageNav.responseStart;
// Request + response time
const requestResponseTime = pageNav.responseEnd - pageNav.requestStart;
Các phép đo khác bạn có thể thực hiện
Thời gian điều hướng và Thời gian tài nguyên hữu ích cho nhiều mục đích hơn những gì các ví dụ trước đã nêu. Sau đây là một số tình huống khác về thời gian liên quan mà bạn nên tìm hiểu:
- Chuyển hướng trang: Chuyển hướng là một nguồn có độ trễ gia tăng mà bạn thường bỏ qua, đặc biệt là các chuỗi chuyển hướng. Độ trễ được thêm theo một số cách, chẳng hạn như các bước chuyển HTTP sang HTTPs, cũng như lệnh chuyển hướng 302/301 không được lưu vào bộ nhớ đệm. Thời gian
redirectStart
,redirectEnd
vàredirectCount
rất hữu ích trong việc đánh giá độ trễ chuyển hướng. - Huỷ tải tài liệu: Trong các trang chạy mã trong trình xử lý sự kiện
unload
, trình duyệt phải thực thi mã đó trước khi có thể chuyển đến trang tiếp theo.unloadEventStart
vàunloadEventEnd
đo lường việc giải phóng tài liệu. - Xử lý tài liệu: Thời gian xử lý tài liệu có thể không quan trọng trừ phi trang web của bạn gửi tải trọng HTML rất lớn. Nếu trường hợp của bạn giống như vậy, thì bạn có thể quan tâm đến các thời gian
domInteractive
,domContentLoadedEventStart
,domContentLoadedEventEnd
vàdomComplete
.
Cách lấy thời gian trong mã
Tất cả các ví dụ đã trình bày đều sử dụng performance.getEntriesByType
, nhưng có những cách khác để truy vấn vùng đệm mục nhập hiệu suất, chẳng hạn như performance.getEntriesByName
và performance.getEntries
. Các phương thức này là phù hợp khi chỉ cần phân tích nhẹ. Tuy nhiên, trong các trường hợp khác, chúng có thể tạo ra quá nhiều thao tác trên luồng chính bằng cách lặp lại trên một số lượng lớn các mục nhập hoặc thậm chí là liên tục thăm dò vùng đệm hiệu suất để tìm các mục nhập mới.
Bạn nên sử dụng PerformanceObserver
để thu thập các mục nhập từ vùng đệm mục nhập hiệu suất. PerformanceObserver
theo dõi các mục nhập hiệu suất và cung cấp các mục đó khi được thêm vào vùng đệm:
// Create the performance observer:
const perfObserver = new PerformanceObserver((observedEntries) => {
// Get all resource entries collected so far:
const entries = observedEntries.getEntries();
// Iterate over entries:
for (let i = 0; i < entries.length; i++) {
// Do the work!
}
});
// Run the observer for Navigation Timing entries:
perfObserver.observe({
type: 'navigation',
buffered: true
});
// Run the observer for Resource Timing entries:
perfObserver.observe({
type: 'resource',
buffered: true
});
Phương thức thu thập thời gian này có thể gây khó chịu khi so sánh với việc truy cập trực tiếp vào vùng đệm mục nhập hiệu suất, nhưng bạn nên liên kết luồng chính với công việc không phục vụ mục đích quan trọng và dành cho người dùng.
Cách gọi điện về nhà
Sau khi thu thập tất cả thời gian cần thiết, bạn có thể gửi các thời gian đó đến một điểm cuối để phân tích thêm. Có hai cách để thực hiện việc này là với navigator.sendBeacon
hoặc fetch
đã đặt tuỳ chọn keepalive
. Cả hai phương thức sẽ gửi yêu cầu tới điểm cuối được chỉ định theo cách không chặn và yêu cầu sẽ được xếp hàng đợi theo cách kéo dài hơn phiên trang hiện tại nếu cần:
// Check for navigator.sendBeacon support:
if ('sendBeacon' in navigator) {
// Caution: If you have lots of performance entries, don't
// do this. This is an example for illustrative purposes.
const data = JSON.stringify(performance.getEntries());
// Send the data!
navigator.sendBeacon('/analytics', data);
}
Trong ví dụ này, chuỗi JSON sẽ đến trong tải trọng POST
mà bạn có thể giải mã, xử lý và lưu trữ trong phần phụ trợ của ứng dụng nếu cần.
Kết luận
Sau khi thu thập các chỉ số, bạn có thể tự tìm hiểu cách phân tích dữ liệu trường đó. Khi phân tích dữ liệu thực địa, bạn cần tuân theo một số quy tắc chung để đảm bảo rằng bạn đang rút ra được những kết luận có ý nghĩa:
- Tránh mức trung bình, vì giá trị này không đại diện cho bất kỳ trải nghiệm nào của một người dùng và có thể bị lệch bởi các điểm ngoại lai.
- Dựa vào phân vị. Trong tập dữ liệu của các chỉ số hiệu suất dựa trên thời gian, chỉ số càng thấp thì càng tốt. Điều này có nghĩa là khi ưu tiên các phân vị thấp, bạn chỉ chú ý đến những trải nghiệm nhanh nhất.
- Ưu tiên phần dài của các giá trị. Khi ưu tiên những trải nghiệm ở phân vị thứ 75 trở lên, bạn đang tập trung vào những trải nghiệm chậm nhất.
Hướng dẫn này không phải là tài nguyên đầy đủ về tính năng Điều hướng hoặc Thời gian tải tài nguyên, mà là một điểm xuất phát. Dưới đây là một số tài nguyên bổ sung mà bạn có thể thấy hữu ích:
- Thông số kỹ thuật về thời gian điều hướng.
- Thông số kỹ thuật về thời gian của tài nguyên.
- ResourceTiming trong thực tế.
- Navigation Timing API (MDN)
- Resource Timing API (MDN)
Nhờ những API này và dữ liệu mà chúng cung cấp, bạn sẽ được trang bị đầy đủ hơn để hiểu rõ hơn trải nghiệm của người dùng thực tế về hiệu suất tải. Nhờ đó, bạn có thể tự tin hơn trong việc chẩn đoán và giải quyết các vấn đề về hiệu suất tải trong trường.