Tối ưu JavaScript (JS) đúng cách giúp tăng tốc độ website

5/5 (1 đánh giá)

Tốc độ tải trang chậm có thể khiến người dùng rời bỏ website của bạn trước khi nội dung được hiển thị đầy đủ, đồng thời làm giảm thứ hạng trên các công cụ tìm kiếm như Google.

Một trong những nguyên nhân chính khiến trang web tải chậm là do xử lý JavaScript (JS) không hiệu quả, đặc biệt là các file JS lớn và tải không đúng cách. Việc tối ưu hóa JavaScript không chỉ giúp tăng tốc website, cải thiện tốc độ tải trang mà còn nâng cao trải nghiệm người dùng và tăng hiệu quả SEO website.

Trong bài viết này, LEDUYNHAT.COM sẽ chia sẻ các kỹ thuật tối ưu JavaScript toàn diện, từ tối ưu mã nguồn, giảm kích thước file JS, đến các chiến lược tải như tải không đồng bộ (async) và trì hoãn (defer), giúp website của bạn hoạt động nhanh hơn và mượt mà hơn.

Xóa JS không sử dụng

Xóa bỏ các đoạn mã và thư viện JavaScript không được sử dụng giúp giảm kích thước cũng như số lượng file JavaScript, giúp tăng hiệu suất tải trang web.

Tuy nhiên, nếu xóa nhầm các đoạn mã hoặc file cần thiết có thể gây lỗi trên trang web. Vì vậy, chúng ta cần phân tích kỹ lưỡng trước khi tiến hành loại bỏ bất kỳ mã hoặc file JavaScript nào.

Bạn có thể sử dụng các công cụ phân tích như Chrome DevTools (tab “Coverage”), Lighthouse, hoặc UnusedJS để phát hiện JavaScript không sử dụng và loại bỏ chúng một cách an toàn.

Giảm nội tuyến JS

JavaScript nội tuyến là các đoạn mã JavaScript được nhúng trực tiếp trong mã HTML, như onclick hoặc trong thẻ <script> ngay trong HTML, thay vì lưu trong các file riêng biệt.

Ví dụ: <button onclick=”alert(‘Hello’)”>Nhấn tôi</button> là JavaScript nội tuyến.

Ví dụ minh họa về JavaScript nội tuyến
Ví dụ minh họa về JavaScript nội tuyến

Việc giảm JavaScript nội tuyến giúp mã nguồn HTML trở nên gọn nhẹ hơn, đồng thời giúp trình duyệt dễ dàng cache các file JavaScript riêng biệt và tái sử dụng chúng trên nhiều trang, từ đó cải thiện hiệu suất tải trang.

Đối với các website lớn, các đoạn mã JavaScript được tái sử dụng nhiều hoặc cần tối ưu hóa cache, bạn nên lưu chúng vào file JavaScript riêng biệt (.js) và tổ chức mã theo cách hợp lý, như tách theo chức năng, minify file, hoặc sử dụng module. Ngược lại, đối với các đoạn mã JavaScript nhỏ, chỉ được sử dụng một lần hoặc rất ngắn, bạn có thể giữ JavaScript nội tuyến để dễ dàng kiểm soát và chỉnh sửa nhanh trong HTML.

Để giảm JavaScript nội tuyến, bạn cần di chuyển các đoạn mã từ HTML sang file .js riêng biệt. Sử dụng các công cụ như Chrome DevTools (tab “Sources” hoặc “Coverage”) để phát hiện mã nội tuyến không cần thiết, sau đó kiểm tra kỹ lưỡng để đảm bảo không gây lỗi trên trang web sau khi di chuyển.

Nén JS

Nén JS (JavaScript Minification) là quá trình loại bỏ các ký tự không cần thiết (như khoảng trắng, dòng trống, chú thích) để giảm kích thước file JS. Bởi vì kích thước file JS nhỏ hơn sẽ giúp giảm thời gian tải, tiết kiệm băng thông, đặc biệt trên các kết nối mạng chậm, đồng thời giảm thời gian phân tích (parsing) và thực thi (execution) bởi trình duyệt.

Nén JS giúp giảm kích thước của tệp
Nén JS giúp giảm kích thước của tệp

Tuy nhiên, sau khi nén mã JS thì nó sẽ trở nên khó đọc, khó sửa lỗi nếu không có file gốc. Bởi vậy, nếu đang trong quá trình phát triển mà vẫn cần kiểm tra mã thì chưa nên nén; ngược lại, hãy nén JS ngay trước khi đưa website vào sử dụng để tối ưu hiệu suất tải trang.

Để thực hiện nén JS thì cách đơn giản nhất là sử dụng plugin, nhưng có thể dẫn đến lỗi web. Bởi vậy, để an toàn thì bạn nên sử dụng phương pháp nén thủ công kết hợp với các công cụ hỗ trợ nén trực tiếp.

Ví dụ minh họa về nén JavaScript (JS)
Ví dụ minh họa về nén JavaScript (JS)

Kết hợp JS

Kết hợp JS (JavaScript Bundling) là gộp nhiều file JS vào một file để giảm số lượng yêu cầu HTTP.

Khi giảm được số lượng yêu cầu HTTP cần thiết sẽ góp phần giúp tăng tốc độ tải trang, nhất là với các trang không hỗ trợ HTTP/2.

Tuy nhiên, nếu không thực hiện đúng cách thì dễ dẫn đến lỗi, đặc biệt là khi web có các thư viện xung đột. Bởi vậy, những website có nhiều file JS nhỏ hoặc khi sử dụng HTTP/1.1 thì hãy cố gắng giảm số lượng file JS. Còn đối với các web sử dụng HTTP/2 thì nên cân nhắc thêm, vì HTTP/2 hỗ trợ tải nhiều file song song.

Để thực hiện việc kết hợp JS thì dễ nhất là sử dụng plugin, nhưng có thể dẫn đến lỗi web. Bởi vậy, để an toàn hơn thì bạn nên phân tích, đánh giá và kết hợp các file JS một cách thủ công.

Trì hoãn tải JS

Trì hoãn tải JavaScript (Deferred Loading) là kỹ thuật trì hoãn việc tải các file JavaScript cho đến khi HTML và CSS tải xong, đảm bảo giao diện hiển thị nhanh hơn trước khi thực thi các script.

Việc này giúp cải thiện tốc độ tải và hiển thị ban đầu (First Contentful Paint) của website, đặc biệt hữu ích cho các script không cần thiết ngay, như animation, tracking, hoặc tương tác bổ sung.

Tuy nhiên, bạn không nên áp dụng kỹ thuật này cho các đoạn mã JavaScript quan trọng cần thực thi ngay khi trang tải, ví dụ như script khởi tạo giao diện hoặc xử lý form. Thay vào đó, chỉ nên sử dụng trì hoãn tải cho các script không cần thiết để hiển thị trang ngay lập tức.

Để thực hiện trì hoãn tải JavaScript, cách phổ biến nhất là sử dụng thuộc tính defer trong thẻ <script> của HTML.

Ví dụ minh họa về trì hoãn tải JavaScript (JS)
Ví dụ minh họa về trì hoãn tải JavaScript (JS)

Đặt JS ở cuối trang

Đặt các thẻ <script> ở cuối trang, ngay trước thẻ đóng </body>, giúp trình duyệt tải và hiển thị HTML, CSS, và các tài nguyên quan trọng trước khi xử lý JavaScript, tránh hiện tượng JavaScript chặn (blocking) việc render trang.

Việc này giúp hiển thị nội dung chính (như văn bản và hình ảnh) nhanh hơn trước khi các script được tải, cải thiện tốc độ tải và hiển thị ban đầu (First Contentful Paint) của trang, vì JavaScript sẽ tải sau cùng trong footer.

Đa số các script của website không quan trọng hoặc không cần thực thi ngay nên được đặt ở cuối trang để tối ưu tốc độ. Tuy nhiên, kỹ thuật này không phù hợp với các đoạn mã JavaScript quan trọng để khởi tạo hoặc xử lý các phần tử giao diện cần hiển thị ngay khi trang tải, như slider hoặc form.

Để thực hiện, bạn chỉ cần đặt các thẻ <script> ngay trước </body> hoặc sử dụng wp_enqueue_script trong WordPress với tham số true để tải script vào footer.

Ví dụ minh họa về đặt JS ở cuối trang
Ví dụ minh họa về đặt JS ở cuối trang

Tải JS không đồng bộ

Tải JavaScript không đồng bộ (Async Loading) cho phép tải các file JavaScript đồng thời với các tài nguyên khác (HTML, CSS) mà không làm gián đoạn việc hiển thị nội dung, giúp trình duyệt hiển thị trang ngay cả khi JavaScript chưa tải xong.

Việc này cải thiện tốc độ hiển thị ban đầu (First Contentful Paint) của trang, tránh tình trạng trang bị chặn render do JavaScript tải đồng bộ. Kỹ thuật này đặc biệt hữu ích cho các script độc lập, như script tracking (Google Analytics) hoặc widget không liên quan đến DOM.

Tuy nhiên, khi sử dụng thuộc tính async, thứ tự thực thi giữa các script không được đảm bảo, vì chúng có thể chạy ngay khi tải xong, bất kể thứ tự trong HTML. Vì vậy, bạn không nên dùng async cho các script cần đảm bảo thứ tự hoặc có sự phụ thuộc, ví dụ script phụ thuộc vào jQuery hoặc cần thực thi theo thứ tự cụ thể. Thay vào đó, chỉ nên áp dụng async cho các script độc lập và không phụ thuộc vào nhau.

Để thực hiện tải JavaScript không đồng bộ, bạn chỉ cần sử dụng thuộc tính async trong thẻ <script>.

Ví dụ minh họa về tải JS không đồng bộ
Ví dụ minh họa về tải JS không đồng bộ

Tải JS có điều kiện

Tải JavaScript có điều kiện là kỹ thuật chỉ tải các script khi đáp ứng điều kiện nhất định, như kích thước màn hình, loại thiết bị, hoặc trang có chứa shortcode, custom post type, hoặc thuộc tính chỉ định.

Khi sử dụng kỹ thuật này, bạn có thể giảm lượng JavaScript tải trong lần tải đầu tiên (giảm kích thước tải và số lượng yêu cầu HTTP) cho các thiết bị hoặc trang không cần đến, điều này cải thiện hiệu suất tải trang ban đầu.

Tuy nhiên, việc sử dụng tải JavaScript có điều kiện có thể làm phức tạp logic code, tăng khó khăn trong việc bảo trì và quản lý điều kiện tải, đồng thời yêu cầu kỹ năng phân tích và kiểm tra kỹ lưỡng để đảm bảo không gây lỗi. Vì vậy, chỉ nên áp dụng trong các trường hợp có yêu cầu tải cụ thể dành riêng cho loại thiết bị, kích thước màn hình, loại trang, hoặc phần tử nhất định.

Cách triển khai tải JavaScript có điều kiện rất linh hoạt và phụ thuộc vào yêu cầu cụ thể của dự án; bạn có thể sử dụng các phương pháp như if, window.matchMedia, hoặc user-agent để xác định điều kiện tải.

Ví dụ minh họa về tải JS có điều kiện
Ví dụ minh họa về tải JS có điều kiện

Trong quá trình triển khai, hai kỹ thuật phổ biến thường được kết hợp với tải có điều kiện là Code Splitting và Lazy Loading JavaScript:

  • Code Splitting là phân chia mã JavaScript thành các file nhỏ hơn, chỉ tải các file đó khi cần thiết thay vì tải tất cả mã cùng lúc.
  • Lazy Loading là chỉ tải các đoạn JavaScript khi chúng thực sự cần thiết, ví dụ khi người dùng cuộn tới một phần nhất định của trang hoặc nhấp vào một phần tử.

Hạn chế dùng thư viện JS bên ngoài

Nên hạn chế sử dụng thư viện JavaScript bên ngoài hoặc tải chúng về máy chủ nội bộ thay vì sử dụng trực tiếp từ CDN bên thứ ba. Việc này giúp cải thiện tốc độ tải trang bằng cách giảm thời gian tải do phụ thuộc vào mạng bên thứ ba hoặc độ trễ CDN, đồng thời giảm phụ thuộc vào các dịch vụ bên ngoài.

Tuy nhiên, việc này có thể tăng dung lượng lưu trữ và băng thông máy chủ, đồng thời yêu cầu cập nhật thủ công khi thư viện có phiên bản mới, dẫn đến tốn thời gian và rủi ro bảo mật nếu không theo dõi phiên bản. Vì vậy, nếu thư viện bên thứ ba cung cấp tốc độ tải nhanh, tự động cập nhật, hoặc có tính năng quan trọng không thể thay thế (như jQuery từ CDN), bạn có thể tiếp tục sử dụng JavaScript bên ngoài.

Để hạn chế sử dụng thư viện JavaScript bên ngoài, hãy đánh giá lợi ích/rủi ro, sau đó tải thư viện về máy chủ, minify và nén file để tối ưu kích thước, rồi gọi nội bộ thay vì sử dụng CDN bên thứ ba.

Tối ưu hóa các hàm JS chặn

Hàm blocking trong JavaScript là các đoạn mã đồng bộ (synchronous) làm chặn (block) main thread của trình duyệt, khiến trình duyệt không thể tiếp tục render hoặc xử lý các tác vụ khác cho đến khi hàm hoàn thành, gây gián đoạn hiệu suất.

Việc loại bỏ hoặc tối ưu hóa các hàm blocking bằng cách loại bỏ nếu không cần thiết, hoặc chuyển sang bất đồng bộ (asynchronous) giúp tránh gián đoạn, đảm bảo hiệu suất mượt mà, và giảm thời gian render trang (First Contentful Paint), cải thiện trải nghiệm người dùng.

Vì vậy, đối với những trang có nhiều mã JavaScript phức tạp và nhiều hàm blocking, việc tối ưu hóa các hàm này rất cần thiết để cải thiện tốc độ tải trang. Tuy nhiên, việc xác định và tối ưu hóa các hàm blocking rất phức tạp và đòi hỏi kiến thức về hiệu suất JavaScript, như sử dụng Web APIs (Web Workers, Promises) và công cụ phân tích (Chrome DevTools).

Để xử lý các hàm blocking đúng cách, bạn cần xác định chính xác chúng bằng cách sử dụng Chrome DevTools (tab “Performance” hoặc “Timeline”) để phát hiện các đoạn mã chặn, sau đó tối ưu hóa hoặc trì hoãn bằng cách chuyển sang bất đồng bộ (sử dụng Promise, async/await, hoặc Web Workers) hoặc trì hoãn bằng setTimeout/requestIdleCallback.

Thay thế JS bằng CSS khi có thể

CSS thường xử lý và render nhanh hơn JavaScript vì nó được trình duyệt tối ưu hóa cho các hiệu ứng và giao diện tĩnh/động đơn giản. Vì vậy, khi có thể, thay vì sử dụng JavaScript cho các hiệu ứng đơn giản như hover, ẩn/hiện, hoặc chuyển động cơ bản, hãy sử dụng CSS để giảm kích thước mã JavaScript, giúp tối ưu tốc độ tải trang.

Tuy nhiên, CSS chỉ phù hợp cho các hiệu ứng đơn giản, trong khi không phù hợp cho các tác vụ phức tạp như xử lý sự kiện chuột phức tạp, tính toán logic, hoặc gọi API.

Bạn cần xem xét và phân tích các hiệu ứng hiện tại bằng cách sử dụng Chrome DevTools (tab “Elements” hoặc “Performance”), nếu chúng đang được xử lý bằng JavaScript mà không cần logic phức tạp, hãy thay thế bằng CSS để tối ưu hóa.

Tối ưu hiệu suất render JS với rAF

requestAnimationFrame (rAF) là API của trình duyệt giúp tối ưu hóa việc render các hiệu ứng animation và cập nhật giao diện bằng cách đồng bộ với tốc độ làm tươi (refresh rate) của màn hình, giúp hiển thị mượt mà hơn và giảm tải CPU so với các phương pháp như setInterval hoặc setTimeout.

Tuy nhiên, requestAnimationFrame không phù hợp cho các tác vụ không liên quan đến render, như gọi API định kỳ, xử lý logic delay, hoặc các tác vụ không cần cập nhật giao diện liên tục. Ngoài ra, bạn cần quản lý hủy rAF đúng cách bằng cách sử dụng cancelAnimationFrame để dừng animation khi không cần thiết, tránh lãng phí tài nguyên.

Để tối ưu hóa hiệu suất render JavaScript cho các hiệu ứng animation cần cập nhật giao diện liên tục theo tốc độ làm tươi của màn hình, hãy dùng requestAnimationFrame kết hợp với cancelAnimationFrame thay vì setInterval hoặc setTimeout.

Prefetch và Preload JavaScript

Prefetch và Preload là các phương pháp giúp trình duyệt tải trước các tài nguyên (gồm JavaScript), nhưng với mục đích khác nhau. Prefetch tải trước các tài nguyên dự đoán sẽ được sử dụng trong các trang hoặc hành động tiếp theo của người dùng. Trong khi đó, Preload tải ngay lập tức các tài nguyên quan trọng cần thiết cho trang hiện tại, để cải thiện tốc độ tải trang đang xem.

Vì vậy, nếu người dùng truy cập vào trang tiếp theo (chuyển trang) và tài nguyên JavaScript đã được Prefetch trước đó, tốc độ tải trang sẽ được cải thiện rất nhiều. Trong khi đó, Preload giúp cải thiện tốc độ tải của trang hiện tại bằng cách ưu tiên tải các tài nguyên quan trọng ngay từ đầu.

Tuy nhiên, việc tải trước các tài nguyên JavaScript có thể gây lãng phí băng thông nếu chúng ít hoặc không được sử dụng. Với Prefetch, lãng phí xảy ra nếu người dùng không truy cập các trang hoặc hành động đã được dự đoán. Với Preload, lãng phí có thể xảy ra nếu tải trước quá nhiều tài nguyên không thực sự quan trọng cho trang hiện tại.

Để prefetch, hãy sử dụng thẻ <link rel=”prefetch” as=”script”> trong HTML để dự đoán và tải trước các tài nguyên JavaScript cho các trang hoặc hành động tiếp theo.

Ví dụ minh họa về prefetch JavaScript (JS)
Ví dụ minh họa về prefetch JavaScript (JS)

Để preload, hãy sử dụng thẻ <link rel=”preload” as=”script”> để tải ngay lập tức các tài nguyên JavaScript quan trọng cần thiết cho trang hiện tại, đảm bảo hiệu suất tốt hơn.

Ví dụ minh họa về preload JavaScript (JS)
Ví dụ minh họa về preload JavaScript (JS)

Sử dụng CDN cho JavaScript

Sử dụng CDN (Content Delivery Network) để phân phối các file JavaScript từ các máy chủ gần người dùng nhất, nó rất hiệu quả cho các website có lượng truy cập lớn và phân bố trên nhiều khu vực địa lý khác nhau. Nó giúp giảm tải máy chủ gốc, tăng tốc độ tải bằng cách tận dụng mạng lưới máy chủ phân bố toàn cầu của CDN và cơ chế cache của trình duyệt.

Mặc dù sử dụng CDN cho JavaScript có thể giúp tăng tốc độ tải trang, nhưng nó không phải lúc nào cũng nhanh hơn so với tải từ máy chủ nội bộ, bởi phụ thuộc vào vị trí người dùng, hiệu suất máy chủ nội bộ và tốc độ CDN. Ví dụ, nếu người dùng ở gần máy chủ nội bộ hoặc CDN gặp sự cố, tải từ máy chủ nội bộ có thể nhanh hơn.

Bên cạnh đó, việc sử dụng CDN làm tăng sự phụ thuộc vào bên thứ ba. Nếu CDN gặp lỗi, bị chặn do chính sách bảo mật (như CSP), hoặc mất kết nối, có thể khiến trang web không hoạt động, gây lỗi. Vì vậy, bạn nên có bản dự phòng, ví dụ sử dụng fallback URL để tải file JavaScript từ máy chủ nội bộ nếu CDN thất bại.

Nếu website nhỏ và có lưu lượng truy cập chủ yếu từ một vị trí địa lý, việc sử dụng CDN có thể mang lại lợi ích không đáng kể về tốc độ và gây lãng phí chi phí CDN hoặc tài nguyên. Thay vào đó, hãy cân nhắc tối ưu máy chủ nội bộ hoặc sử dụng cơ chế cache cục bộ.

Hãy kết hợp linh hoạt các kỹ thuật tối ưu JavaScript phía trên để giúp cải thiện tốc độ tải trang, tăng hiệu suất website và nâng cao trải nghiệm người dùng. Bằng cách tối ưu cách JS được tải và thực thi, bạn có thể giảm kích thước file, giảm tải cho máy chủ và đảm bảo trang web hoạt động mượt mà hơn, góp phần cải thiện SEO và giữ chân người dùng tốt hơn.

Bài viết thuộc chuyên mục:
Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Bài viết cùng chủ đề