API thời gian người dùng

Tìm hiểu về ứng dụng web

Alex Danilo

Ứng dụng web có hiệu suất cao là yếu tố quan trọng để mang lại trải nghiệm tuyệt vời cho người dùng. Khi các ứng dụng web ngày càng trở nên phức tạp, việc hiểu rõ tác động đến hiệu suất là yếu tố quan trọng để tạo ra trải nghiệm hấp dẫn. Trong vài năm qua, một số API khác nhau đã xuất hiện trong trình duyệt để giúp phân tích hiệu suất của mạng, thời gian tải, v.v. nhưng những API này không nhất thiết cung cấp thông tin chi tiết với đủ tính linh hoạt để tìm ra nguyên nhân làm chậm ứng dụng của bạn. Nhập User Timing API (API Thời gian người dùng). API này cung cấp một cơ chế mà bạn có thể dùng để đo lường ứng dụng web của mình nhằm xác định thời gian mà ứng dụng của bạn dành cho từng hoạt động. Trong bài viết này, chúng ta sẽ tìm hiểu về API này cùng với các ví dụ về cách sử dụng.

Bạn không thể tối ưu hoá những gì mình không thể đo lường

Bước đầu tiên để tăng tốc một ứng dụng web chậm là tìm ra thời gian đang được dành cho việc gì. Đo lường mức độ ảnh hưởng về thời gian của các vùng mã JavaScript là cách lý tưởng để xác định các điểm nóng, đây là bước đầu tiên để tìm cách cải thiện hiệu suất. May mắn là User Timing API cung cấp một cách để bạn có thể chèn lệnh gọi API vào các phần khác nhau của Javascript, sau đó trích xuất dữ liệu thời gian chi tiết có thể dùng để giúp bạn tối ưu hoá.

Thời gian phân giải cao và now()

Một phần cơ bản của việc đo lường thời gian chính xác là độ chính xác. Trước đây, chúng ta có thời gian dựa trên phép đo mili giây, nhưng việc xây dựng một trang web 60 FPS không bị giật có nghĩa là mỗi khung hình cần được vẽ trong 16 mili giây. Vì vậy, khi bạn chỉ có độ chính xác đến mili giây, thì độ chính xác đó không đủ để phân tích hiệu quả. Hãy nhập High Resolution Time (Thời gian có độ phân giải cao), một loại thời gian mới được tích hợp vào các trình duyệt hiện đại. High Resolution Time cung cấp cho chúng ta dấu thời gian dấu phẩy động có thể chính xác đến độ phân giải micro giây – tốt hơn một nghìn lần so với trước đây.

Để lấy thời gian hiện tại trong ứng dụng web, hãy gọi phương thức now(), phương thức này tạo thành một phần mở rộng của giao diện Performance. Đoạn mã sau đây cho biết cách thực hiện việc đó:

var myTime = window.performance.now();

Có một giao diện khác tên là PerformanceTiming cung cấp một số thời gian khác nhau liên quan đến cách tải ứng dụng web của bạn. Phương thức now() trả về thời gian đã trôi qua kể từ khi navigationStartthời gian trong PerformanceTiming xảy ra.

Loại DOMHighResTimeStamp

Trước đây, khi cố gắng tính thời gian cho các ứng dụng web, bạn sẽ sử dụng một hàm như Date.now() để trả về DOMTimeStamp. DOMTimeStamp trả về một số nguyên mili giây làm giá trị của nó. Để cung cấp độ chính xác cao hơn cần thiết cho thời gian có độ phân giải cao, một loại mới có tên là DOMHighResTimeStamp đã được ra mắt. Loại này là một giá trị dấu phẩy động cũng trả về thời gian tính bằng mili giây. Nhưng vì là dấu phẩy động, nên giá trị này có thể biểu thị mili giây phân số và do đó có thể mang lại độ chính xác bằng một phần nghìn mili giây.

Giao diện Thời gian người dùng

Giờ đây, khi đã có dấu thời gian có độ phân giải cao, hãy sử dụng giao diện Thời gian người dùng để lấy thông tin về thời gian.

Giao diện Thời gian người dùng cung cấp các hàm cho phép chúng ta gọi các phương thức ở nhiều vị trí trong ứng dụng, từ đó cung cấp một đường dẫn breadcrumb theo kiểu Hansel và Gretel để giúp chúng ta theo dõi thời gian được sử dụng ở đâu.

Sử dụng mark()

Phương thức mark() là công cụ chính trong bộ công cụ phân tích thời gian của chúng tôi. mark() sẽ lưu trữ dấu thời gian cho chúng ta. Điều cực kỳ hữu ích về mark() là chúng ta có thể đặt tên cho dấu thời gian và API sẽ ghi nhớ tên cũng như dấu thời gian dưới dạng một đơn vị duy nhất.

Việc gọi mark() tại nhiều vị trí trong ứng dụng giúp bạn biết được thời gian cần thiết để đạt được "mốc" đó trong ứng dụng web.

Thông số kỹ thuật này đưa ra một số tên đề xuất cho các điểm đánh dấu có thể thú vị và khá dễ hiểu, chẳng hạn như mark_fully_loaded, mark_fully_visible,mark_above_the_fold, v.v.

Ví dụ: chúng ta có thể đặt dấu mốc cho thời điểm ứng dụng được tải đầy đủ bằng cách sử dụng mã sau:

window.performance.mark('mark_fully_loaded');

Bằng cách đặt các dấu được đặt tên trong ứng dụng web, chúng ta có thể thu thập toàn bộ dữ liệu về thời gian và phân tích dữ liệu đó theo ý muốn để tìm hiểu xem ứng dụng đang làm gì và khi nào.

Tính toán số đo bằng measure()

Sau khi đặt một loạt dấu thời gian, bạn sẽ muốn tìm hiểu thời gian đã trôi qua giữa các dấu thời gian đó. Bạn sử dụng phương thức measure() để thực hiện việc đó.

Phương thức measure() tính toán thời gian đã trôi qua giữa các điểm đánh dấu và cũng có thể đo lường thời gian giữa điểm đánh dấu của bạn và bất kỳ tên sự kiện phổ biến nào trong giao diện PerformanceTiming.

Ví dụ: bạn có thể tính thời gian từ khi DOM hoàn tất cho đến khi trạng thái ứng dụng được tải đầy đủ bằng cách sử dụng mã như:

window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');

Khi bạn gọi measure(), hàm này sẽ lưu trữ kết quả độc lập với các dấu bạn đặt, nhờ đó bạn có thể truy xuất các dấu đó sau này. Bằng cách lưu trữ thời gian khi ứng dụng chạy, ứng dụng vẫn thích ứng và bạn có thể kết xuất tất cả dữ liệu sau khi ứng dụng hoàn tất một số công việc để có thể phân tích sau.

Đang loại bỏ các dấu bằng clearMarks()

Đôi khi, bạn nên loại bỏ một loạt dấu mà bạn đã thiết lập. Ví dụ: bạn có thể chạy hàng loạt trên ứng dụng web của mình và do đó, bạn muốn bắt đầu mới mỗi lần chạy.

Bạn có thể dễ dàng loại bỏ mọi điểm đánh dấu đã thiết lập bằng cách gọi clearMarks().

Vì vậy, mã ví dụ bên dưới sẽ xoá tất cả các dấu hiện có để bạn có thể thiết lập lại một lần chạy tính thời gian nếu muốn.

window.performance.clearMarks();

Tất nhiên, có một số trường hợp bạn không muốn xoá tất cả các điểm đánh dấu. Vì vậy, nếu muốn loại bỏ các điểm đánh dấu cụ thể, bạn chỉ cần truyền tên của điểm đánh dấu mà bạn muốn xoá. Ví dụ: đoạn mã dưới đây:

window.performance.clearMarks('mark_fully_loaded');

sẽ loại bỏ dấu mà chúng ta đặt trong ví dụ đầu tiên, đồng thời giữ nguyên mọi dấu khác mà chúng ta đặt.

Bạn cũng có thể muốn loại bỏ mọi phép đo đã thực hiện và có một phương thức tương ứng để thực hiện việc đó, gọi là clearMeasures(). Công cụ này hoạt động giống hệt như clearMarks(), nhưng thay vào đó, công cụ này hoạt động trên mọi phép đo lường mà bạn đã thực hiện. Ví dụ: mã:

window.performance.clearMeasures('measure_load_from_dom');

sẽ xoá chỉ số mà chúng ta đã tạo trong ví dụ về measure() ở trên. Nếu muốn xoá tất cả các chỉ số, bạn có thể thực hiện tương tự như clearMarks() – tức là chỉ cần gọi clearMeasures() mà không cần đối số.

Lấy dữ liệu về thời gian

Việc đặt dấu và đo lường khoảng thời gian là rất tốt, nhưng đến một lúc nào đó, bạn sẽ muốn lấy dữ liệu thời gian đó để thực hiện một số phân tích. Việc này cũng rất đơn giản, bạn chỉ cần sử dụng giao diện PerformanceTimeline.

Ví dụ: phương thức getEntriesByType() cho phép chúng ta lấy tất cả thời gian đánh dấu hoặc tất cả thời gian đo lường dưới dạng danh sách để có thể lặp lại và phân tích dữ liệu. Điều thú vị là danh sách này được trả về theo thứ tự thời gian, vì vậy, bạn có thể thấy các dấu theo thứ tự mà chúng được nhấn trong ứng dụng web của bạn.

Mã bên dưới:

var items = window.performance.getEntriesByType('mark');

trả về cho chúng ta danh sách tất cả các điểm đánh dấu đã được kích hoạt trong ứng dụng web, trong khi mã:

var items = window.performance.getEntriesByType('measure');

trả về danh sách tất cả các phép đo mà chúng ta đã thực hiện.

Bạn cũng có thể lấy lại danh sách các mục bằng cách sử dụng tên cụ thể mà bạn đã đặt cho các mục đó. Ví dụ: mã:

var items = window.performance.getEntriesByName('mark_fully_loaded');

sẽ trả về cho chúng ta một danh sách có một mục chứa dấu thời gian "mark_fully_loaded" trong thuộc tính startTime.

Đo thời gian của một yêu cầu XHR (ví dụ)

Giờ đây, khi đã có hình dung rõ ràng về API Thời gian người dùng, chúng ta có thể sử dụng API này để phân tích thời gian thực hiện tất cả XMLHttpRequests trong ứng dụng web.

Trước tiên, chúng ta sẽ sửa đổi tất cả các yêu cầu send() để đưa ra một lệnh gọi hàm thiết lập các điểm đánh dấu, đồng thời thay đổi lệnh gọi lại thành công bằng một lệnh gọi hàm đặt một điểm đánh dấu khác, sau đó tạo một thước đo về thời gian thực hiện yêu cầu.

Vì vậy, thông thường XMLHttpRequest của chúng ta sẽ có dạng như sau:

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  do_something(e.responseText);
}
myReq.send();

Trong ví dụ này, chúng ta sẽ thêm một bộ đếm chung để theo dõi số lượng yêu cầu, đồng thời sử dụng bộ đếm này để lưu trữ một số đo cho mỗi yêu cầu được thực hiện. Mã để thực hiện việc này có dạng như sau:

var reqCnt = 0;

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  window.performance.mark('mark_end_xhr');
  reqCnt++;
  window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
  do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();

Đoạn mã trên tạo ra một phép đo có giá trị tên riêng biệt cho mỗi XMLHttpRequest mà chúng ta gửi. Chúng tôi giả định rằng các yêu cầu chạy theo trình tự – mã cho các yêu cầu song song sẽ cần phức tạp hơn một chút để xử lý các yêu cầu trả về không theo thứ tự, chúng tôi sẽ để phần này làm bài tập cho người đọc.

Sau khi ứng dụng web thực hiện một loạt yêu cầu, chúng ta có thể kết xuất tất cả các yêu cầu đó vào bảng điều khiển bằng mã dưới đây:

var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
  var req = items[i];
  console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}

Kết luận

API Thời gian người dùng cung cấp cho bạn nhiều công cụ hữu ích để áp dụng cho mọi khía cạnh của ứng dụng web. Bạn có thể dễ dàng thu hẹp các điểm truy cập trong ứng dụng bằng cách rải các lệnh gọi API trong ứng dụng web và xử lý hậu kỳ dữ liệu thời gian được tạo để có được bức tranh rõ ràng về nơi thời gian đang được sử dụng. Nhưng nếu trình duyệt của bạn không hỗ trợ API này thì sao? Không sao cả, bạn có thể tìm thấy polyfill tuyệt vời tại đây. Polyfill này mô phỏng API rất tốt và cũng hoạt động hiệu quả với webpagetest.org. Vậy bạn còn chờ gì nữa? Hãy thử dùng API Thời gian người dùng trên ứng dụng của bạn ngay bây giờ. Bạn sẽ tìm ra cách tăng tốc ứng dụng và người dùng sẽ cảm ơn bạn vì đã mang đến cho họ trải nghiệm tốt hơn nhiều.