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 chất lượng cao cho người dùng. Khi các ứng dụng web ngày càng trở nên phức tạp hơn, việc hiểu rõ tác động đến hiệu suất là điều cần thiết để 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 mạng, thời gian tải, v.v. nhưng các API này không nhất thiết phải cung cấp thông tin chi tiết với đủ 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 của người dùng). API này cung cấp một cơ chế mà bạn có thể sử dụng để đo lường ứng dụng web nhằm xác định nơi ứng dụng của bạn đang dành thời gian. 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 API.

Bạn không thể tối ưu hoá những gì 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 hiểu thời gian đang được sử dụng. Đo lường tác động theo 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, là bước đầu tiên trong việc tìm ra cách cải thiện hiệu suất. May mắn thay, User Timing API (API đo lường thời gian của người dùng) cung cấp một cách để bạn có thể chèn lệnh gọi API vào nhiều phần 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 có độ phân giải cao và now()

Độ chính xác là một phần cơ bản của việc đo lường thời gian chính xác. Trước đây, chúng ta có thời gian dựa trên phép đo mili giây là chấp nhận được, nhưng việc xây dựng trang web 60 khung hình/giây 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 đó sẽ không đủ để phân tích hiệu quả. 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. Thời gian có độ phân giải cao 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 gấp 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 Hiệu suất. 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 có tên là PerformanceTiming (Thời gian hiệu suất) cung cấp một số thời gian khác nhau liên quan đến cách ứng dụng web của bạn được tải. Phương thức now() trả về thời gian đã trôi qua kể từ khi thời gian navigationStart 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ị. Để cung cấp độ chính xác cao hơn cần thiết cho thời gian Độ phân giải cao, một loại mới có tên là DOMHighResTimeStamp đã được giới thiệu. 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. Tuy nhiên, vì là dấu phẩy động nên giá trị này có thể biểu thị mili giây thập phân 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 tính 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 User Timing (Thời gian của người dùng) để lấy thông tin về thời gian.

Giao diện User Timing (Đo lường thời gian của 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. Các phương thức này có thể cung cấp dấu vết đường dẫn kiểu Hansel và Gretel để cho phép chúng ta theo dõi thời gian đang được sử dụng.

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. Việc mark() làm là lưu trữ một 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 và dấu thời gian dưới dạng một đơn vị.

Việc gọi mark() ở nhiều vị trí trong ứng dụng cho phép bạn tính toán thời gian cần thiết để đạt được "điểm đánh dấu" đó trong ứng dụng web.

Thông số kỹ thuật nêu một số tên đề xuất cho các 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 một dấu cho thời điểm ứng dụng tải xong bằng cách sử dụng mã sau:

window.performance.mark('mark_fully_loaded');

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

Tính toán số liệu đo lường bằng measure()

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

Phương thức measure() tính thời gian đã trôi qua giữa các điểm đánh dấu, đồng thời 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 nào phổ biến 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ư sau:

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 mà 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 chờ khi ứng dụng chạy, ứng dụng vẫn có khả năng phản hồi 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ỏ nhãn bằng clearMarks()

Đôi khi, bạn cần xoá một loạt các 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 và muốn bắt đầu lại mỗi lần chạy.

Bạn có thể dễ dàng xoá mọi 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 điểm đánh 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 nên xoá tất cả các dấu. Vì vậy, nếu muốn loại bỏ các dấu cụ thể, bạn chỉ cần đặt tên của dấu mà bạn muốn xoá. Ví dụ: mã dưới đây:

window.performance.clearMarks('mark_fully_loaded');

sẽ xoá dấu mà chúng ta đặt trong ví dụ đầu tiên trong khi 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 biện pháp mà mình đã thực hiện. Có một phương thức tương ứng để thực hiện việc đó có tên là clearMeasures(). Phương thức này hoạt động giống hệt như clearMarks(), nhưng hoạt động trên mọi phép đo mà bạn đã thực hiện. Ví dụ: mã:

window.performance.clearMeasures('measure_load_from_dom');

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

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

Việc đặt điểm đánh dấu và đo lường khoảng thời gian là rất tốt, nhưng tại một thời điểm nào đó, bạn muốn có 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à tổng hợp dữ liệu. Điều thú vị là danh sách đượ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.

Mã bên dưới:

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

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

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

trả về danh sách tất cả các biện pháp 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 nhập bằng cách sử dụng tên cụ thể mà bạn đã đặt cho các mục nhập đó. 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.

Xác định thời gian cho một yêu cầu XHR (ví dụ)

Giờ đây, khi đã nắm được rõ ràng về User Timing API, chúng ta có thể sử dụng API này để phân tích thời gian cần thiết cho tất cả cá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 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 lệnh gọi hàm thiết lập một điểm đánh dấu khác, sau đó tạo một phép đo 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 toàn cục để theo dõi số lượng yêu cầu và cũng để sử dụng bộ đếm đó lưu trữ một biện pháp đo lường cho mỗi yêu cầu được thực hiện. Mã để thực hiện việc này sẽ 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();

Mã ở trên tạo một chỉ số có giá trị tên riêng biệt cho mỗi XMLHttpRequest mà chúng ta gửi. Chúng ta giả định các yêu cầu chạy tuần 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 ta sẽ để đó làm bài tập cho người đọc.

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ả yêu cầu đó vào bảng điều khiển bằng cách sử dụng mã bên dưới:

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 của người dùng cung cấp cho bạn nhiều công cụ tuyệt vời để á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 nóng trong ứng dụng bằng cách rải các lệnh gọi API trong toàn bộ ứng dụng web và xử lý sau dữ liệu thời gian được tạo để tạo ra bức tranh rõ ràng về 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, bạn có thể tìm thấy một polyfill tuyệt vời tại đây mô phỏng API rất tốt và hoạt động hiệu quả với webpagetest.org. Vậy bạn còn chờ gì nữa? Hãy thử User Timing API trên các ứng dụng của bạn ngay bây giờ. Bạn sẽ tìm ra cách tăng tốc độ cho các ứng dụng đó và người dùng sẽ cảm ơn bạn vì đã mang đến trải nghiệm tốt hơn nhiều.