Web Performance Made dễ dàng – Google I/O phiên bản 2018

Tại Google IO 2018, chúng tôi đã trình bày một bản tóm tắt về các công cụ, thư viện và kỹ thuật tối ưu hóa giúp cải thiện hiệu suất web dễ dàng hơn. Ở đây, chúng tôi giải thích các phương pháp này bằng ứng dụng The Oodles5. Ngoài ra, chúng tôi cũng nói về các thử nghiệm của mình với tính năng tải dự đoán và sáng kiến Measurement.js mới.

Addy Osmani
Addy Osmani
Ewa Gasperowicz

Trong năm qua, chúng tôi đã khá bận rộn để tìm cách làm cho môi trường Web nhanh hơn và hiệu quả hơn. Điều này đã mang đến các công cụ, phương pháp tiếp cận và thư viện mới mà chúng tôi muốn chia sẻ với bạn trong bài viết này. Trong phần đầu, chúng tôi sẽ giới thiệu một số kỹ thuật tối ưu hoá mà chúng tôi đã sử dụng trong thực tế khi phát triển ứng dụng Oodles5. Trong phần thứ hai, chúng tôi sẽ nói về các thử nghiệm của mình với tính năng tải dự đoán và sáng kiến mới Guess.js.

Nhu cầu về hiệu suất

Mỗi năm, Internet ngày càng nặng nề hơn. Nếu kiểm tra trạng thái của web, chúng tôi có thể thấy rằng một trang trung bình trên thiết bị di động có kích thước khoảng 1,5 MB, với phần lớn là JavaScript và hình ảnh.

Kích thước ngày càng tăng của các trang web, cùng với các yếu tố khác, như độ trễ mạng, giới hạn của CPU, các mẫu chặn hiển thị hoặc mã của bên thứ ba không cần thiết, góp phần vào câu đố phức tạp về hiệu suất.

Hầu hết người dùng đều đánh giá tốc độ là yếu tố hàng đầu trong hệ phân cấp trải nghiệm người dùng với nhu cầu của họ. Điều này không quá bất ngờ vì bạn thực sự không thể làm được nhiều việc cho đến khi trang tải xong. Bạn không thể nhận dạng giá trị từ trang, bạn không thể ngưỡng mộ tính thẩm mỹ của trang đó.

piramide cho hệ phân cấp trải nghiệm người dùng
Hình 1. Tốc độ có vai trò quan trọng như thế nào đối với người dùng? (Speed Matters, Tập 3)

Chúng tôi biết rằng hiệu suất quan trọng đối với người dùng, nhưng chúng tôi cũng bí mật để biết nên bắt đầu tối ưu hoá từ đâu. Rất may là có những công cụ có thể giúp bạn trong quá trình này.

Lighthouse – cơ sở cho quy trình hiệu suất

Lighthouse là một phần của Công cụ của Chrome cho nhà phát triển cho phép bạn kiểm tra trang web của mình và đưa ra gợi ý về cách cải thiện trang web.

Gần đây, chúng tôi đã triển khai một loạt quy trình kiểm tra hiệu suất mới thực sự hữu ích trong quy trình phát triển hằng ngày.

Kiểm tra Lighthouse mới
Hình 2. Các bước kiểm tra Lighthouse mới

Hãy cùng khám phá cách bạn có thể tận dụng những tính năng này thông qua một ví dụ thực tế: ứng dụng Oodles rạp chiếu phim. Đây là một ứng dụng web minh hoạ, bạn có thể dùng thử một số hình tượng trưng tương tác của Google mà chúng tôi yêu thích và thậm chí chơi một vài trò chơi.

Trong khi tạo ứng dụng, chúng tôi muốn đảm bảo rằng ứng dụng hoạt động hiệu quả nhất có thể. Điểm xuất phát để tối ưu hoá là báo cáo Lighthouse.

Báo cáo Lighthouse cho ứng dụng Oodles
Hình 3. Báo cáo Lighthouse cho ứng dụng Oodles

Hiệu suất ban đầu của ứng dụng theo như thấy trong báo cáo Lighthouse là khá tệ. Trên mạng 3G, người dùng cần đợi 15 giây để hiển thị nội dung có ý nghĩa đầu tiên hoặc để ứng dụng có khả năng tương tác. Lighthouse đã nêu bật rất nhiều vấn đề với trang web của chúng tôi và điểm hiệu suất tổng thể là 23 đã phản ánh chính xác điều đó.

Trang có trọng lượng khoảng 3,4 MB – chúng tôi rất cần giảm bớt một chút chất béo.

Đây là thách thức đầu tiên về hiệu suất của chúng tôi: tìm những thứ chúng tôi có thể dễ dàng gỡ bỏ mà không ảnh hưởng đến trải nghiệm tổng thể.

Cơ hội tối ưu hoá hiệu suất

Xoá tài nguyên không cần thiết

Có một số thành phần hiển nhiên có thể được xoá một cách an toàn: khoảng trắng và nhận xét.

Lợi nhuận từ việc giảm thiểu
Hình 4. Rút gọn và nén JavaScript và CSS

Lighthouse nêu bật cơ hội này trong Kiểm tra CSS và JavaScript chưa được tối ưu hóa. Chúng tôi đã sử dụng gói web cho quy trình xây dựng. Vì vậy, để rút gọn, chúng tôi chỉ cần sử dụng trình bổ trợ Uglify JS.

Rút gọn là một nhiệm vụ phổ biến, vì vậy, bạn có thể tìm được giải pháp có sẵn cho bất kỳ quy trình xây dựng nào mà bạn sử dụng.

Một cách kiểm tra hữu ích khác trong không gian đó là Cho phép nén văn bản. Không có lý do để gửi tệp không nén và hiện nay, hầu hết các CDN đều hỗ trợ việc này ngay từ đầu.

Chúng tôi đã sử dụng tính năng Lưu trữ Firebase để lưu trữ mã và Firebase sẽ bật tính năng gzip theo mặc định, vì vậy, nhờ việc lưu trữ mã trên CDN ở mức hợp lý, chúng tôi đã nhận được dịch vụ này miễn phí.

Mặc dù gzip là cách nén rất phổ biến, nhưng các cơ chế khác như ZopfliBrotli cũng thu hút được sự chú ý. Brotli thích được hỗ trợ trong hầu hết các trình duyệt và bạn có thể sử dụng tệp nhị phân để nén sẵn thành phần trước khi gửi đến máy chủ.

Sử dụng các chính sách bộ nhớ đệm hiệu quả

Bước tiếp theo của chúng tôi là đảm bảo rằng chúng tôi không gửi tài nguyên hai lần nếu không cần thiết.

Quy trình kiểm tra Chính sách bộ nhớ đệm không hiệu quả trong Lighthouse đã giúp chúng tôi nhận thấy rằng chúng tôi có thể tối ưu hoá các chiến lược lưu vào bộ nhớ đệm của mình để đạt được chính xác điều đó. Bằng cách thiết lập tiêu đề hết hạn tuổi tối đa trong máy chủ, chúng tôi đảm bảo rằng trong một lần truy cập lặp lại, người dùng có thể sử dụng lại các tài nguyên họ đã tải xuống trước đó.

Tốt nhất là bạn nên lưu vào bộ nhớ đệm nhiều tài nguyên nhất có thể một cách an toàn trong khoảng thời gian dài nhất có thể và cung cấp mã thông báo xác thực để xác thực lại hiệu quả các tài nguyên đã cập nhật.

Xoá các đoạn mã không dùng đến

Cho đến nay, chúng ta đã xoá các phần rõ ràng trong tệp tải xuống không cần thiết, nhưng các phần ít rõ ràng hơn thì sao? Ví dụ: mã không dùng đến.

Mức độ sử dụng mã trong Công cụ cho nhà phát triển
Hình 5. Kiểm tra mức độ phù hợp của mã

Đôi khi, chúng ta đưa vào mã ứng dụng những thứ không thực sự cần thiết. Điều này đặc biệt xảy ra nếu bạn làm việc trên ứng dụng trong một thời gian dài, nhóm hoặc các phần phụ thuộc của bạn sẽ thay đổi và đôi khi một thư viện mất nguồn gốc bị bỏ lại phía sau. Đó chính xác là những gì đã xảy ra với chúng tôi.

Ban đầu, chúng tôi sử dụng thư viện Thành phần Material để nhanh chóng tạo nguyên mẫu cho ứng dụng của mình. Sau đó, chúng tôi chuyển sang một giao diện tuỳ chỉnh hơn và quên hoàn toàn thư viện đó. Rất may là việc kiểm tra mức độ sử dụng mã đã giúp chúng tôi phát hiện lại mã này trong gói.

Bạn có thể kiểm tra số liệu thống kê về mức độ sử dụng mã trong Công cụ cho nhà phát triển, cả đối với thời gian chạy cũng như thời gian tải của ứng dụng. Bạn có thể thấy hai sọc lớn màu đỏ trong ảnh chụp màn hình dưới cùng – chúng tôi có hơn 95% CSS không được sử dụng và cũng có rất nhiều JavaScript.

Lighthouse cũng đã phát hiện vấn đề này trong quá trình kiểm tra các quy tắc CSS chưa sử dụng. Loại chiến dịch này có khả năng tiết kiệm hơn 400 kb. Vì vậy, chúng tôi đã quay lại mã của mình và xoá cả phần JavaScript và CSS trong thư viện đó.

Nếu thả bộ chuyển đổi MVC, kiểu của chúng ta sẽ giảm xuống còn 10KB
Hình 6. Nếu thả bộ chuyển đổi MVC, kiểu của chúng ta sẽ giảm xuống còn 10KB!

Điều này đã giúp gói CSS của chúng tôi giảm xuống 20 lần, khá tốt cho một cam kết nhỏ, dài hai dòng.

Tất nhiên, điều này đã giúp điểm hiệu suất của chúng tôi tăng lên và Thời gian tương tác cũng tốt hơn nhiều.

Tuy nhiên, với những thay đổi như thế này thì vẫn chưa đủ để bạn kiểm tra chỉ số và điểm số của mình. Việc xoá mã thực tế không bao giờ không có rủi ro, vì vậy, bạn phải luôn chú ý đến khả năng hồi quy.

Mã của chúng tôi đã được sử dụng trong 95% – vẫn còn 5% này ở đâu đó. Rõ ràng là một trong những thành phần của chúng tôi vẫn đang sử dụng kiểu trong thư viện đó – các mũi tên nhỏ trong thanh trượt hình tượng trưng. Vì kích thước này rất nhỏ nên chúng ta có thể kết hợp lại các kiểu đó theo cách thủ công vào các nút.

Các nút bị lỗi do thiếu thư viện
Hình 7. Một thành phần vẫn đang sử dụng thư viện bị xoá

Vì vậy, nếu xoá mã, bạn chỉ cần đảm bảo có sẵn một quy trình kiểm thử phù hợp để tránh xảy ra sự hồi quy trực quan.

Tránh tải trọng mạng lớn

Chúng tôi biết rằng các tài nguyên lớn có thể làm chậm quá trình tải trang web. Chúng có thể khiến người dùng tốn chi phí và chúng có thể ảnh hưởng lớn đến gói dữ liệu của họ, vì vậy, bạn cần lưu ý đến điều này.

Lighthouse đã phát hiện ra vấn đề với một số tải trọng mạng bằng cách sử dụng quy trình kiểm tra Tải trọng mạng rất lớn.

Phát hiện tải trọng mạng khổng lồ
Hình 8. Phát hiện tải trọng mạng khổng lồ

Ở đây, chúng tôi thấy rằng chúng tôi có hơn 3 triệu mã đang được chuyển xuống – con số này khá nhiều, đặc biệt là trên thiết bị di động.

Ở đầu danh sách này, Lighthouse đã làm nổi bật việc chúng tôi có một gói nhà cung cấp JavaScript gồm 2mb mã không nén. Đây cũng là vấn đề được gói web làm nổi bật.

Như người ta hay nói: yêu cầu nhanh nhất là yêu cầu không được thực hiện.

Tốt nhất là bạn nên đo lường giá trị của từng thành phần mà bạn đang phân phát cho người dùng, đo lường hiệu suất của các thành phần đó và xác định xem có thực sự nên chuyển sang trải nghiệm ban đầu hay không. Vì đôi khi những thành phần này có thể bị trì hoãn hoặc tải từng phần hoặc được xử lý trong thời gian không hoạt động.

Trong trường hợp của chúng tôi, vì đang xử lý rất nhiều gói JavaScript, nên chúng tôi rất may mắn vì cộng đồng JavaScript có một bộ công cụ kiểm tra gói JavaScript phong phú.

Kiểm tra gói JavaScript
Hình 9. Kiểm tra gói JavaScript

Chúng tôi bắt đầu bằng trình phân tích gói webpack, cho biết rằng chúng tôi đã đưa vào một phần phụ thuộc có tên là unicode, với 1,6 MB JavaScript đã được phân tích cú pháp, vì vậy, rất nhiều.

Sau đó, chúng tôi đã chuyển đến trình chỉnh sửa và sử dụng Trình bổ trợ chi phí nhập cho mã trực quan, chúng tôi có thể hình dung chi phí của mọi mô-đun mà mình nhập. Điều này cho phép chúng tôi phát hiện thành phần nào chứa mã tham chiếu đến mô-đun này.

Sau đó, chúng tôi đã chuyển sang sử dụng một công cụ khác là BundlePhobia. Đây là công cụ cho phép bạn nhập tên của bất kỳ gói ALIAS nào và xem thực tế kích thước thu nhỏ và nén của gói đó là như thế nào. Chúng tôi đã tìm thấy một giải pháp thay thế tuyệt vời cho mô-đun sên mà chúng tôi đang sử dụng, mô-đun này chỉ có trọng lượng 2,2 kb và vì vậy chúng tôi đã chuyển đổi mô-đun đó lên.

Điều này có tác động lớn đến hiệu suất của chúng tôi. Trong khoảng thời gian từ thay đổi này và khám phá các cơ hội khác để giảm kích thước gói JavaScript, chúng tôi đã tiết kiệm được 2,1 MB mã.

Chúng tôi nhận thấy cải thiện tổng thể 65% sau khi bạn tính đến kích thước nén và thu nhỏ của các gói này. Và chúng tôi nhận thấy rằng việc này thực sự đáng để thực hiện.

Vì vậy, nói chung, hãy cố gắng loại bỏ những nội dung tải xuống không cần thiết trên trang web và ứng dụng của bạn. Việc tạo khoảng không quảng cáo cho tài sản và đo lường tác động của hiệu suất có thể tạo nên sự khác biệt thực sự lớn. Vì vậy, hãy nhớ kiểm tra tài sản của mình khá thường xuyên.

Giảm thời gian khởi động JavaScript nhờ tính năng chia tách mã

Mặc dù tải trọng mạng lớn có thể có tác động lớn đến ứng dụng, nhưng có một thứ khác có thể tác động thực sự lớn, đó là JavaScript.

JavaScript là tài sản đắt nhất. Trên thiết bị di động, nếu bạn gửi xuống các gói JavaScript lớn, thì việc này có thể làm chậm thời gian người dùng có thể tương tác với các thành phần giao diện người dùng. Điều đó có nghĩa là họ có thể nhấn vào giao diện người dùng mà không thực sự bất kỳ điều gì có ý nghĩa xảy ra. Vì vậy, điều quan trọng là chúng tôi phải hiểu tại sao JavaScript lại tốn kém đến vậy.

Đây là cách trình duyệt xử lý JavaScript.

Xử lý JavaScript
Hình 10. Xử lý JavaScript

Trước hết, chúng ta phải tải tập lệnh đó xuống, chúng ta có một công cụ JavaScript cần phân tích cú pháp mã đó, biên dịch và thực thi mã.

Hiện tại, các giai đoạn này không tốn nhiều thời gian trên một thiết bị cao cấp như máy tính để bàn hoặc máy tính xách tay, thậm chí là điện thoại cao cấp. Nhưng trên điện thoại di động trung bình, quá trình này có thể mất từ 5 đến 10 lần. Đây là điều làm chậm trễ hoạt động tương tác, vì vậy, chúng ta cần cố gắng cắt giảm phần này.

Để giúp bạn phát hiện những vấn đề này với ứng dụng của mình, chúng tôi đã giới thiệu tính năng kiểm tra thời gian khởi động JavaScript mới cho Lighthouse.

Thời gian khởi động JavaScript
Hình 11. Kiểm tra thời gian khởi động JavaScript

Trong trường hợp của ứng dụng Oodle, nó cho biết thời gian khởi động JavaScript là 1,8 giây. Vấn đề xảy ra là chúng tôi nhập tĩnh tất cả các tuyến và thành phần vào một gói JavaScript nguyên khối.

Một kỹ thuật để giải quyết vấn đề này là sử dụng phân chia mã.

Việc chia tách mã giống như pizza

Chia tách mã là khái niệm thay vì cung cấp cho người dùng toàn bộ JavaScript bằng một chiếc bánh pizza. Điều gì sẽ xảy ra nếu bạn chỉ cho họ một lát mỗi lần khi họ cần?

Bạn có thể áp dụng chế độ phân tách mã ở cấp định tuyến hoặc cấp thành phần. Công cụ này hoạt động hiệu quả với React and React Loadable, Vue.js, Angular, Polymer, Preact và nhiều thư viện khác.

Chúng tôi đã kết hợp tính năng phân tách mã vào ứng dụng của mình, chuyển từ phương thức nhập tĩnh sang nhập động, cho phép chúng ta tải từng phần một cách không đồng bộ mã khi cần.

Phân tách mã bằng tính năng nhập động
Hình 13. Việc phân tách mã bằng tính năng nhập động

Tác động của việc này vừa giảm kích thước các gói, vừa giảm thời gian khởi động JavaScript. Nó giảm xuống còn 0,78 giây, giúp ứng dụng nhanh hơn 56%.

Nhìn chung, nếu bạn đang xây dựng một trải nghiệm nặng về JavaScript, hãy nhớ chỉ gửi mã cho người dùng mà họ cần.

Hãy tận dụng các khái niệm như phân tách mã, khám phá các ý tưởng như rung cây và xem kho lưu trữ webpack-libs-optimizations để biết một vài ý tưởng về cách bạn có thể giảm bớt kích thước thư viện của mình nếu đang sử dụng gói web.

Tối ưu hóa hình ảnh

Câu đùa về hiệu suất tải hình ảnh

Trong ứng dụng Oodle, chúng ta đang sử dụng rất nhiều hình ảnh. Thật không may, Lighthouse không còn hào hứng với trò chơi này hơn nhiều so với chúng tôi. Trên thực tế, chúng tôi không đạt được cả ba cuộc kiểm tra liên quan đến hình ảnh.

Chúng tôi quên tối ưu hoá hình ảnh, định cỡ hình ảnh không chính xác và cũng có thể đạt được một số lợi ích khi sử dụng các định dạng hình ảnh khác.

Kiểm tra hình ảnh
Hình 14. Kiểm tra hình ảnh Lighthouse

Chúng tôi bắt đầu tối ưu hoá hình ảnh của mình.

Đối với vòng tối ưu hoá một lần, bạn có thể sử dụng các công cụ trực quan như ImageOptim hoặc XNConvert.

Một phương pháp tự động hơn là thêm một bước tối ưu hoá hình ảnh vào quy trình xây dựng, với các thư viện như imagemin.

Bằng cách này, bạn đảm bảo rằng hình ảnh được thêm trong tương lai sẽ được tự động tối ưu hoá. Một số CDN (chẳng hạn như Akamai hoặc các giải pháp của bên thứ ba như Cloudinary, Nhanh chóng hoặc Uploadcare) cung cấp cho bạn các giải pháp tối ưu hoá hình ảnh toàn diện. Nhờ đó, bạn cũng có thể chỉ cần lưu trữ hình ảnh trên các dịch vụ đó.

Nếu bạn không muốn làm điều đó vì vấn đề chi phí hoặc độ trễ, thì các dự án như Thumbor hoặc Imageflow sẽ cung cấp các lựa chọn thay thế tự lưu trữ.

Trước và sau khi tối ưu hoá
Hình 15. Trước và sau khi tối ưu hoá

PNG nền của chúng tôi đã được gắn cờ trong gói web là lớn và đúng như vậy. Sau khi định kích thước chính xác cho khung nhìn và chạy qua ImageOptim, chúng tôi đã giảm xuống còn 100 kb, điều này là chấp nhận được.

Việc lặp lại quy trình này cho nhiều hình ảnh trên trang web đã giúp chúng tôi giảm đáng kể trọng lượng tổng thể của trang.

Dùng định dạng phù hợp cho nội dung động

Ảnh GIF có thể rất tốn kém. Điều đáng ngạc nhiên là ban đầu, định dạng GIF chưa bao giờ được dùng làm nền tảng ảnh động. Do đó, việc chuyển sang định dạng video phù hợp hơn sẽ giúp bạn tiết kiệm lớn về kích thước tệp.

Trong ứng dụng Oodle, chúng ta đã sử dụng ảnh GIF làm chuỗi giới thiệu trên trang chủ. Theo Lighthouse, chúng tôi có thể tiết kiệm hơn 7 MB bằng cách chuyển sang định dạng video hiệu quả hơn. Đoạn video của chúng tôi có trọng số khoảng 7,3mb, quá nhiều so với mọi trang web hợp lý.Vì vậy, thay vào đó, chúng tôi đã chuyển đoạn video đó thành một phần tử video với hai tệp nguồn – một tệp mp4 và WebM để hỗ trợ nhiều trình duyệt hơn.

Thay thế GIF động bằng video
Hình 16. Thay thế GIF động bằng video

Chúng tôi đã sử dụng công cụ FFmpeg để chuyển đổi ảnh động GIF thành tệp mp4. Định dạng WebM mang lại cho bạn khoản tiết kiệm thậm chí còn lớn hơn – API ImageOptim có thể thực hiện việc chuyển đổi đó cho bạn.

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

Chúng tôi đã cố gắng tiết kiệm hơn 80% tổng trọng số nhờ chuyển đổi này. Điều này khiến chúng tôi giảm xuống còn khoảng 1 MB.

Tuy nhiên, 1mb là tài nguyên lớn để giảm đường truyền, đặc biệt là đối với người dùng trên băng thông bị hạn chế. Thật may là chúng ta có thể sử dụng API Loại hiệu quả để nhận ra các thiết bị này đang ở trên băng thông chậm và thay vào đó cung cấp cho chúng một tệp JPEG nhỏ hơn nhiều.

Giao diện này sử dụng thời gian khứ hồi hiệu quả và giá trị giảm dần để ước tính loại mạng mà người dùng đang sử dụng. Nó chỉ đơn giản là trả về một chuỗi, 2G, 2G, 3G hoặc 4G chậm. Vì vậy, tuỳ thuộc vào giá trị này, nếu người dùng có thiết bị dưới 4G, chúng ta có thể thay thế phần tử video bằng hình ảnh.

if (navigator.connection.effectiveType) { ... }

Trang web đó giảm bớt một chút khỏi trải nghiệm, nhưng ít nhất thì trang web đó vẫn dùng được trên kết nối chậm.

Tải từng phần hình ảnh ngoài màn hình

Các băng chuyền, thanh trượt hoặc các trang thực sự dài thường tải hình ảnh, mặc dù người dùng không thể thấy chúng ngay trên trang.

Lighthouse sẽ gắn cờ hành vi này trong quá trình kiểm tra hình ảnh ngoài màn hình và bạn cũng có thể tự mình xem hành vi này trong bảng điều khiển mạng của Công cụ cho nhà phát triển. Nếu bạn thấy rất nhiều hình ảnh được gửi đến trong khi chỉ một số ít hình ảnh xuất hiện trên trang, thì tức là bạn có thể cân nhắc việc tải từng phần.

Tính năng tải từng phần chưa được hỗ trợ sẵn trong trình duyệt. Vì vậy, chúng ta phải sử dụng JavaScript để thêm tính năng này. Chúng tôi sử dụng thư viện Lazysizes để thêm hành vi tải từng phần vào các ảnh bìa Oodle.

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

Lazysizes là một công cụ thông minh vì không chỉ theo dõi các thay đổi về chế độ hiển thị của phần tử, mà còn chủ động tìm nạp trước các phần tử ở gần khung hiển thị để mang lại trải nghiệm tối ưu cho người dùng. Ngoài ra, API này còn tích hợp IntersectionObserver không bắt buộc, giúp bạn tra cứu chế độ hiển thị rất hiệu quả.

Sau khi có sự thay đổi này, hình ảnh của chúng tôi sẽ được tìm nạp theo yêu cầu. Nếu bạn muốn tìm hiểu sâu hơn về chủ đề đó, hãy xem images.guide – một tài nguyên rất hữu ích và toàn diện.

Giúp trình duyệt phân phối sớm các tài nguyên quan trọng

Không phải mọi byte được chuyển xuống dây đến trình duyệt đều có cùng mức độ quan trọng và trình duyệt biết điều này. Nhiều trình duyệt có thông tin phỏng đoán để quyết định xem nên tìm nạp nội dung nào trước tiên. Vì vậy, đôi khi chúng sẽ tìm nạp CSS trước hình ảnh hoặc tập lệnh.

Có thể có ích là chúng tôi, với tư cách là tác giả của trang, cho trình duyệt biết điều gì thực sự quan trọng đối với chúng tôi. Rất may là trong vài năm qua, các nhà cung cấp trình duyệt đã bổ sung một số tính năng để giúp chúng tôi về vấn đề này, ví dụ: gợi ý về tài nguyên như link rel=preconnect, preload hoặc prefetch.

Những khả năng này được đưa đến nền tảng web giúp trình duyệt tìm nạp đúng thời điểm và hiệu quả hơn một chút so với một số phương pháp tải tuỳ chỉnh, dựa trên logic được thực hiện bằng cách sử dụng tập lệnh.

Hãy xem Lighthouse thực sự hướng dẫn chúng ta sử dụng một số tính năng này như thế nào một cách hiệu quả.

Điều đầu tiên Lighthouse yêu cầu chúng ta làm là tránh nhiều chuyến đi khứ hồi tốn kém đến bất kỳ điểm khởi hành nào.

Tránh nhiều chuyến đi khứ hồi tốn kém đến bất kỳ điểm khởi hành nào
Hình 17. Tránh nhiều chuyến đi khứ hồi tốn kém đến bất kỳ điểm khởi hành nào

Trong trường hợp của ứng dụng Oodle, chúng ta thực sự đang sử dụng rất nhiều Google Fonts. Bất cứ khi nào bạn thả một biểu định kiểu Google Font vào trang của mình, biểu định kiểu đó sẽ kết nối tối đa 2 miền con. Những gì Lighthouse chúng tôi biết là nếu có thể khởi động kết nối đó, chúng tôi có thể tiết kiệm đến 300 mili giây trong thời gian kết nối ban đầu.

Tận dụng lợi thế của việc kết nối trước liên kết, chúng ta có thể che giấu độ trễ kết nối đó một cách hiệu quả.

Đặc biệt với những phông chữ như Google Fonts nơi CSS mặt phông chữ của chúng tôi được lưu trữ trên googleapis.com và các tài nguyên phông chữ của chúng tôi được lưu trữ trên Gstatic, điều này có thể có tác động rất lớn. Vì vậy, chúng tôi đã áp dụng phương pháp tối ưu hoá này và tiết kiệm được vài trăm mili giây.

Điều tiếp theo mà Lighthouse đề xuất là chúng ta nên tải trước các yêu cầu chính.

Tải trước các yêu cầu chính
Hình 18. Tải trước các yêu cầu chính

<link rel=preload> thực sự mạnh mẽ, nó thông báo cho trình duyệt rằng cần có tài nguyên trong thành phần điều hướng hiện tại và cố gắng khiến trình duyệt tìm nạp tài nguyên đó càng sớm càng tốt.

Giờ đây, Lighthouse cho chúng ta biết rằng chúng ta nên tải trước các tài nguyên phông chữ quan trọng trên web, vì chúng ta đang tải trong hai phông chữ web.

Tải trước phông chữ trên web có dạng như sau – chỉ định rel=preload, bạn truyền vào as cùng với loại phông chữ, sau đó chỉ định loại phông chữ mình đang cố gắng tải, chẳng hạn như woff2.

Ảnh hưởng của việc này đối với trang của bạn khá rõ ràng.

Tác động của việc tải trước tài nguyên
Hình 19. Tác động của việc tải trước tài nguyên

Thông thường, bạn không cần sử dụng tính năng tải trước rel liên kết, nếu phông chữ web quan trọng đối với trang của bạn, thì trước tiên trình duyệt phải tìm nạp HTML, phân tích cú pháp CSS và ở nơi sau đó, cuối cùng trình duyệt sẽ tìm nạp phông chữ trên web của bạn.

Bằng cách sử dụng tính năng tải trước rel liên kết, ngay sau khi trình duyệt đã phân tích cú pháp HTML của bạn, trình duyệt thực sự có thể bắt đầu tìm nạp các phông chữ web đó sớm hơn nhiều. Trong ứng dụng của chúng ta, tính năng này đã giúp chúng ta giảm bớt một giây thời gian cần thiết để hiển thị văn bản bằng phông chữ web.

Thực tế sẽ không đơn giản như vậy nếu bạn muốn thử tải trước phông chữ bằng Google Fonts, có một getcha.

URL phông chữ của Google mà chúng tôi chỉ định trên mặt phông chữ trong biểu định kiểu của mình là thứ mà nhóm phông chữ cập nhật khá thường xuyên. Các URL này có thể hết hạn hoặc được cập nhật theo tần suất thông thường. Vì vậy, nếu muốn kiểm soát hoàn toàn trải nghiệm tải phông chữ, bạn nên tự lưu trữ phông chữ trên web của mình. Điều này có thể tuyệt vời vì nó cho phép bạn truy cập vào những nội dung như tải trước rel liên kết.

Trong trường hợp của chúng tôi, chúng tôi nhận thấy công cụ Google Web Fonts Helper thực sự hữu ích trong việc giúp chúng tôi ngoại tuyến một số phông chữ web đó và thiết lập chúng trên thiết bị. Vì vậy, hãy kiểm tra công cụ đó.

Cho dù bạn đang sử dụng phông chữ trên web như một phần của tài nguyên quan trọng hay sử dụng JavaScript, hãy cố gắng giúp trình duyệt phân phối các tài nguyên quan trọng của bạn càng sớm càng tốt.

Thử nghiệm: Gợi ý về mức độ ưu tiên

Chúng tôi có một điều đặc biệt muốn chia sẻ với bạn hôm nay. Ngoài các tính năng như gợi ý về tài nguyên, cũng như tải trước, chúng tôi còn đang xây dựng một tính năng trình duyệt thử nghiệm hoàn toàn mới mà chúng tôi gọi là gợi ý ưu tiên.

Đặt mức độ ưu tiên cho nội dung hiển thị ban đầu
Hình 20. Gợi ý ưu tiên

Đây là tính năng mới cho phép bạn gợi ý cho trình duyệt về tầm quan trọng của tài nguyên. Tính năng này hiển thị một thuộc tính mới – mức độ quan trọng – với các giá trị thấp, cao hoặc tự động.

Điều này cho phép chúng tôi truyền tải mức độ ưu tiên của các tài nguyên ít quan trọng hơn, chẳng hạn như kiểu, hình ảnh không quan trọng, hoặc tìm nạp lệnh gọi API để giảm mức độ tranh chấp. Chúng tôi cũng có thể tăng mức độ ưu tiên cho những nội dung quan trọng hơn, như hình ảnh chính.

Trong trường hợp của ứng dụng Oodle, điều này thực sự đã giúp chúng tôi tối ưu hoá một cách thiết thực.

Đặt mức độ ưu tiên cho nội dung hiển thị ban đầu
Hình 21. Đặt mức độ ưu tiên cho nội dung hiển thị ban đầu

Trước khi chúng tôi thêm tính năng tải từng phần vào hình ảnh của mình, nhiệm vụ mà trình duyệt đang thực hiện là băng chuyền hình ảnh này với tất cả các hình tượng trưng và trình duyệt đang tìm nạp tất cả hình ảnh ngay từ đầu băng chuyền có mức độ ưu tiên cao ngay từ đầu. Thật không may, hình ảnh ở giữa băng chuyền mới lại quan trọng nhất đối với người dùng. Vì vậy, chúng tôi đặt mức độ quan trọng của các hình nền đó ở mức rất thấp, hình nền ở mức rất cao, tác động chỉ trong 2 giây đối với mạng 3G chậm và tốc độ tìm nạp cũng như kết xuất những hình ảnh đó. Đó là một trải nghiệm tích cực tốt đẹp.

Chúng tôi hy vọng có thể cung cấp tính năng này cho Canary trong vài tuần tới, vì vậy hãy chú ý theo dõi thông tin đó.

Có chiến lược tải phông chữ trên web

Kiểu chữ là yếu tố cơ bản để tạo ra một thiết kế tốt. Nếu đang dùng phông chữ trên web, thì bạn không muốn chặn hiển thị văn bản cũng như chắc chắn không muốn hiện văn bản không hiển thị.

Hiện tại, chúng tôi sẽ làm nổi bật nội dung này trong Lighthouse, với việc kiểm tra tránh văn bản ẩn trong khi phông chữ trên web đang tải.

Tránh văn bản ẩn trong khi Phông chữ trên web đang tải
Hình 22. Tránh văn bản ẩn trong khi Phông chữ trên web đang tải

Nếu tải phông chữ trên web bằng một khối phông chữ, bạn sẽ cho phép trình duyệt quyết định việc cần làm nếu mất nhiều thời gian để tìm nạp phông chữ web đó. Một số trình duyệt sẽ chờ ở bất kỳ đâu lên đến 3 giây để thực hiện việc này trước khi quay lại phông chữ hệ thống và cuối cùng sẽ hoán đổi phông chữ đó thành phông chữ sau khi được tải xuống.

Chúng tôi đang cố gắng tránh văn bản bị ẩn này, vì vậy trong trường hợp này, chúng tôi sẽ không thể xem các hình tượng trưng cổ điển của tuần này nếu phông chữ trên web mất quá nhiều thời gian. Rất may, với tính năng mới có tên là font-display, bạn thực sự có nhiều quyền kiểm soát hơn đối với quy trình này.

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

Chế độ hiển thị phông chữ giúp bạn quyết định cách phông chữ trên web sẽ hiển thị hoặc dự phòng dựa trên khoảng thời gian hoán đổi các phông chữ đó.

Trong trường hợp này, chúng ta sẽ sử dụng hoán đổi màn hình phông chữ. Tính năng hoán đổi cung cấp cho mặt phông chữ một khoảng thời gian khối 0 giây và một khoảng thời gian hoán đổi vô hạn. Tức là trình duyệt sẽ vẽ văn bản của bạn gần như ngay lập tức bằng phông chữ dự phòng nếu phông chữ đó mất một chút thời gian để tải. Giao diện này sẽ thay đổi khi phông chữ có sẵn.

Trong ứng dụng của chúng ta, lý do lại tuyệt vời là việc này cho phép chúng ta hiển thị một số văn bản có ý nghĩa ngay từ đầu và chuyển sang phông chữ web sau khi sẵn sàng.

Kết quả hiển thị phông chữ
Hình 23. Kết quả hiển thị phông chữ

Nhìn chung, nếu bạn đang sử dụng phông chữ trên web, như phần lớn web sử dụng, hãy triển khai một chiến lược tải phông chữ trang web hiệu quả.

Có rất nhiều tính năng trên nền tảng web mà bạn có thể sử dụng để tối ưu hoá trải nghiệm tải phông chữ, nhưng cũng nên xem kho lưu trữ Công thức phông chữ trên web của Zach daman, vì nó thực sự tuyệt vời.

Giảm các tập lệnh chặn hiển thị

Có những phần khác trong ứng dụng mà chúng ta có thể đẩy sớm hơn trong chuỗi tải xuống để cung cấp ít nhất một số trải nghiệm người dùng cơ bản sớm hơn một chút.

Trên chuỗi tiến trình của Lighthouse, bạn có thể thấy rằng trong vài giây đầu tiên này khi tất cả các tài nguyên đang tải, người dùng thực sự không thể thấy bất kỳ nội dung nào.

Giảm cơ hội biểu định kiểu chặn hiển thị
Hình 24. Giảm cơ hội biểu định kiểu chặn hiển thị

Việc tải xuống và xử lý các biểu định kiểu bên ngoài đang khiến quá trình kết xuất của chúng tôi không thể thực hiện bất kỳ tiến trình nào.

Chúng ta có thể cố gắng tối ưu hoá đường dẫn hiển thị quan trọng bằng cách phân phối một số kiểu sớm hơn một chút.

Nếu chúng ta trích xuất các kiểu chịu trách nhiệm cho lần hiển thị ban đầu này và cùng dòng với các kiểu đó trong HTML, thì trình duyệt có thể hiển thị các kiểu đó ngay lập tức mà không cần đợi biểu định kiểu bên ngoài đến.

Trong trường hợp này, chúng ta đã sử dụng một mô-đun SSID có tên là Critical (Quan trọng) để chèn nội dung quan trọng vào cùng dòng trong index.html trong bước xây dựng.

Mặc dù mô-đun này đã đảm nhận phần lớn phần việc nặng nhọc cho chúng tôi, nhưng vẫn còn một chút khó khăn để đảm bảo quá trình này hoạt động trơn tru trên nhiều tuyến.

Nếu bạn không cẩn thận hoặc cấu trúc trang web của bạn thực sự phức tạp, có thể bạn sẽ rất khó để ra mắt loại mẫu này nếu không có kế hoạch cho cấu trúc giao diện ứng dụng ngay từ đầu.

Đây là lý do tại sao bạn phải sớm cân nhắc về hiệu suất. Nếu không thiết kế để đạt hiệu suất ngay từ đầu, thì rất có thể bạn sẽ gặp vấn đề khi thực hiện việc này sau này.

Cuối cùng, rủi ro đã được đền đáp, chúng tôi đã giải quyết được vấn đề và ứng dụng bắt đầu phân phối nội dung sớm hơn nhiều, cải thiện đáng kể thời gian hiển thị đáng kể đầu tiên.

Kết quả

Đó là một danh sách dài các phương pháp tối ưu hoá hiệu suất mà chúng tôi đã áp dụng cho trang web của mình. Hãy cùng xem kết quả. Đây là cách ứng dụng của chúng ta tải trên một thiết bị di động cỡ trung bình trên mạng 3G, trước và sau khi tối ưu hoá.

Điểm hiệu suất của Lighthouse tăng từ 23 lên 91. Đó là tiến bộ khá tốt về tốc độ. Tất cả các thay đổi này đều được thực hiện nhờ việc chúng tôi liên tục kiểm tra và thực hiện theo báo cáo Lighthouse. Nếu bạn muốn biết cách chúng tôi triển khai tất cả các điểm cải tiến về mặt kỹ thuật bằng kỹ thuật, hãy xem kho lưu trữ của chúng tôi, đặc biệt là tại những công ty PR đã hạ cánh ở đó.

Hiệu suất dự đoán – trải nghiệm người dùng dựa trên dữ liệu

Chúng tôi tin rằng công nghệ học máy mang đến một cơ hội thú vị cho tương lai trong nhiều lĩnh vực. Một ý tưởng mà chúng tôi hy vọng sẽ tạo ra nhiều thử nghiệm hơn trong tương lai là dữ liệu thực có thể thực sự định hướng trải nghiệm người dùng mà chúng tôi đang tạo ra.

Ngày nay, chúng ta thực hiện rất nhiều quyết định tuỳ ý về những gì người dùng có thể muốn hoặc cần, từ đó xác định những dữ liệu đáng được tìm nạp trước, tải trước hoặc lưu trước vào bộ nhớ đệm. Nếu đoán đúng thì chúng tôi có thể ưu tiên một số ít tài nguyên, nhưng thực sự khó mở rộng phạm vi tài nguyên đó cho toàn bộ trang web.

Chúng tôi thực sự có sẵn dữ liệu để làm cơ sở tốt hơn cho các biện pháp tối ưu hoá của mình hiện nay. Khi sử dụng API Báo cáo Google Analytics, chúng tôi có thể xem trang trên cùng tiếp theo và tỷ lệ phần trăm thoát của mọi URL trên trang web, từ đó đưa ra kết luận về tài nguyên mà chúng tôi nên ưu tiên.

Nếu kết hợp việc này với một mô hình xác suất tốt, chúng ta sẽ tránh lãng phí dữ liệu của người dùng bằng cách tích cực tìm nạp trước nội dung. Chúng tôi có thể tận dụng dữ liệu đó của Google Analytics, đồng thời sử dụng công nghệ học máy và các mô hình như chuỗi Markov hoặc mạng nơron để triển khai các mô hình như vậy.

Gói theo hướng dữ liệu cho các ứng dụng web
Hình 25. Gói dựa trên dữ liệu cho ứng dụng web

Để hỗ trợ thử nghiệm này, chúng tôi vui mừng thông báo một sáng kiến mới mà chúng tôi có tên là Guess.js.

Guess.js
Hình 26. Đoán.js

Measurement.js là một dự án tập trung vào trải nghiệm người dùng dựa trên dữ liệu cho web. Chúng tôi hy vọng rằng ý tưởng này sẽ truyền cảm hứng cho việc khám phá cách sử dụng dữ liệu để cải thiện hiệu suất web và hơn thế nữa. Tất cả đều là nguồn mở và có sẵn trên GitHub hiện nay. Tính năng này được xây dựng với sự cộng tác với cộng đồng nguồn mở của Minko Gechev, Kyle Matthews đến từ Gatsby, Katie Hempenius và một số người khác.

Hãy truy cập vào Đoán.js và cho chúng tôi biết suy nghĩ của bạn.

Tóm tắt

Các điểm số và chỉ số rất hữu ích trong việc cải thiện tốc độ của web, nhưng chỉ là phương tiện chứ không phải là mục tiêu.

Tất cả chúng ta đều từng gặp phải tình trạng tải trang chậm khi di chuyển, nhưng giờ đây chúng ta có cơ hội mang đến cho người dùng trải nghiệm thú vị hơn khi tải thực sự nhanh chóng.

Cải thiện hiệu suất là cả một hành trình. Rất nhiều thay đổi nhỏ có thể mang lại lợi ích lớn. Bằng cách sử dụng các công cụ tối ưu hoá phù hợp và theo dõi các báo cáo Lighthouse, bạn có thể cung cấp trải nghiệm tốt hơn và toàn diện hơn cho người dùng của mình.

Đặc biệt cảm ơn các nhà sáng tạo như: Town Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Wang, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse và Google Hình tượng trưng.