Tối ưu hoá độ trễ khi nhập

Tìm hiểu độ trễ đầu vào là gì và tìm hiểu các kỹ thuật giảm thiểu độ trễ để tương tác nhanh hơn.

Tương tác trên web là những điều phức tạp, với tất cả các loại hoạt động đều diễn ra trong trình duyệt để thúc đẩy tương tác. Tuy nhiên, điểm chung của tất cả các hàm này là phải chịu một chút độ trễ đầu vào trước khi các lệnh gọi lại sự kiện bắt đầu chạy. Trong hướng dẫn này, bạn sẽ tìm hiểu về độ trễ đầu vào và những việc bạn có thể làm để giảm thiểu độ trễ này, nhờ đó, các lượt tương tác trên trang web của bạn chạy nhanh hơn.

Độ trễ khi nhập là gì?

Độ trễ đầu vào là khoảng thời gian kể từ khi người dùng tương tác với một trang lần đầu tiên (chẳng hạn như nhấn vào màn hình, nhấp bằng chuột hoặc nhấn một phím) cho đến khi lệnh gọi lại sự kiện cho lượt tương tác bắt đầu chạy. Mỗi lượt tương tác đều bắt đầu với độ trễ đầu vào nào đó.

Hình ảnh đơn giản về độ trễ đầu vào. Ở bên trái có hình minh hoạ con trỏ chuột với vệt sao phía sau, báo hiệu sự bắt đầu tương tác. Ở bên phải là hình minh hoạ đường kẻ, biểu thị thời điểm trình xử lý sự kiện cho một hoạt động tương tác bắt đầu chạy. Khoảng cách ở giữa được ghi chú là độ trễ đầu vào bằng dấu ngoặc nhọn.
Cơ chế đằng sau độ trễ khi nhập. Khi hệ điều hành nhận được dữ liệu đầu vào, dữ liệu đó phải được chuyển đến trình duyệt trước khi bắt đầu tương tác. Quá trình này mất một khoảng thời gian nhất định và có thể tăng lên bằng công việc luồng chính hiện có.

Một số phần chậm trễ đầu vào là không thể tránh khỏi: luôn mất một khoảng thời gian để hệ điều hành nhận dạng sự kiện đầu vào và chuyển sự kiện đó đến trình duyệt. Tuy nhiên, độ trễ nhập đó thường không đáng kể. Ngoài ra, có những vấn đề khác xảy ra trên trang cũng có thể khiến việc nhập dữ liệu bị trễ đủ lâu và gây ra vấn đề.

Tìm hiểu về độ trễ khi nhập thông tin

Nói chung, bạn nên giữ cho mọi phần của lượt tương tác ở mức ngắn nhất có thể để trang web của bạn đạt ngưỡng "tốt" của chỉ số Tương tác với nội dung hiển thị tiếp theo (INP), bất kể thiết bị của người dùng là gì. Việc duy trì độ trễ đầu vào trong kiểm tra chỉ là một phần trong việc đáp ứng ngưỡng đó.

Do đó, bạn sẽ cần nhắm đến độ trễ đầu vào ngắn nhất có thể để đạt ngưỡng "tốt" của INP. Tuy nhiên, bạn nên lưu ý rằng không thể loại bỏ hoàn toàn độ trễ đầu vào. Miễn là bạn tránh quá nhiều thao tác trên luồng chính trong khi người dùng đang cố gắng tương tác với trang của bạn, thời gian chờ nhập sẽ đủ thấp để tránh sự cố.

Cách giảm thiểu độ trễ khi nhập

Như đã đề cập trước đó, một số độ trễ đầu vào là không thể tránh khỏi, nhưng mặt khác, một số độ trễ đầu vào có thể tránh được. Dưới đây là một số điều cần xem xét nếu bạn gặp khó khăn khi nhập dữ liệu chậm trễ kéo dài.

Tránh các đồng hồ hẹn giờ định kỳ khiến luồng chính phải thực hiện quá nhiều thao tác

Có 2 hàm bộ tính giờ thường dùng trong JavaScript có thể góp phần vào độ trễ đầu vào: setTimeoutsetInterval. Điểm khác biệt giữa 2 công cụ này là setTimeout lên lịch để chạy một lệnh gọi lại sau một thời gian cụ thể. Mặt khác, setInterval lên lịch một lệnh gọi lại để chạy vĩnh viễn mỗi n mili giây hoặc cho đến khi bộ tính giờ được dừng bằng clearInterval.

Bản thân setTimeout không phải là vấn đề. Trên thực tế, nó có thể hữu ích trong việc tránh các thao tác dài. Tuy nhiên, điều này phụ thuộc vào thời điểm hết thời gian chờ và liệu người dùng có cố gắng tương tác với trang khi lệnh gọi lại thời gian chờ chạy hay không.

Ngoài ra, setTimeout có thể chạy trong vòng lặp hoặc đệ quy, trong đó nó hoạt động giống như setInterval hơn, mặc dù tốt nhất là không lên lịch vòng lặp tiếp theo cho đến khi vòng lặp trước đó hoàn tất. Mặc dù điều này có nghĩa là vòng lặp sẽ dẫn đến luồng chính mỗi khi setTimeout được gọi, nhưng bạn nên chú ý để đảm bảo lệnh gọi lại của lệnh gọi lại không thực hiện quá nhiều thao tác.

setInterval chạy lệnh gọi lại trong một khoảng thời gian nên có nhiều khả năng gây cản trở các hoạt động tương tác. Điều này là do không giống như một thực thể của lệnh gọi setTimeout, là lệnh gọi lại một lần có thể cản trở người dùng tương tác — bản chất định kỳ của setInterval khiến khả năng cao là sẽ cản trở một lượt tương tác, từ đó làm tăng độ trễ đầu vào của hoạt động tương tác.

Ảnh chụp màn hình trình phân tích hiệu suất trong Công cụ của Chrome cho nhà phát triển minh hoạ độ trễ đầu vào. Tác vụ được kích hoạt bởi hàm bộ tính giờ xảy ra ngay trước khi người dùng bắt đầu tương tác nhấp chuột. Tuy nhiên, bộ tính giờ sẽ kéo dài độ trễ đầu vào, khiến các lệnh gọi lại sự kiện của tương tác chạy muộn hơn so với bình thường.
Bộ tính giờ được đăng ký bởi lệnh gọi setInterval trước đó góp phần vào độ trễ đầu vào như mô tả trong bảng hiệu suất của Công cụ của Chrome cho nhà phát triển. Độ trễ đầu vào tăng thêm khiến các lệnh gọi lại sự kiện cho hoạt động tương tác chạy muộn hơn so với bình thường.

Nếu đồng hồ hẹn giờ xuất hiện trong mã của bên thứ nhất, thì bạn có quyền kiểm soát các đồng hồ hẹn giờ đó. Hãy đánh giá xem bạn có cần chúng hay không, hoặc cố gắng hết sức để giảm bớt công việc trong chúng nhiều nhất có thể. Tuy nhiên, đồng hồ hẹn giờ trong tập lệnh của bên thứ ba lại là một câu chuyện khác. Bạn thường không có quyền kiểm soát hoạt động của tập lệnh của bên thứ ba và việc khắc phục các vấn đề về hiệu suất trong mã của bên thứ ba thường đòi hỏi bạn phải làm việc với các bên liên quan để xác định xem tập lệnh của bên thứ ba có cần thiết hay không. Nếu có, hãy liên hệ với nhà cung cấp tập lệnh bên thứ ba để xác định những việc có thể làm để khắc phục các vấn đề về hiệu suất mà tập lệnh này có thể gây ra trên trang web của bạn.

Tránh các thao tác dài

Một cách để giảm độ trễ đầu vào kéo dài là tránh các tác vụ dài. Khi bạn có quá nhiều tác vụ luồng chính chặn luồng chính trong quá trình tương tác, điều này sẽ làm tăng độ trễ đầu vào trước khi các tác vụ dài có cơ hội hoàn tất.

Hình ảnh trực quan về khoảng thời gian các tác vụ kéo dài độ trễ đầu vào. Ở trên cùng, hoạt động tương tác xảy ra ngay sau khi chạy một tác vụ dài, gây ra độ trễ đầu vào đáng kể, khiến các lệnh gọi lại sự kiện chạy muộn hơn nhiều so với bình thường. Ở dưới cùng, một hoạt động tương tác xảy ra gần như cùng một lúc, nhưng tác vụ cần nhiều thời gian được chia nhỏ thành nhiều phần nhỏ hơn bằng cách tạo ra, cho phép các lệnh gọi lại sự kiện của hoạt động tương tác chạy sớm hơn nhiều.
Hình ảnh trực quan về những gì sẽ xảy ra với các tác vụ tương tác khi các tác vụ quá dài và trình duyệt không thể phản hồi đủ nhanh với các tác vụ so với khi các tác vụ dài hơn được chia thành các tác vụ nhỏ hơn.

Bên cạnh việc giảm thiểu khối lượng công việc bạn thực hiện trong một tác vụ – và bạn luôn nên cố gắng làm ít công việc nhất có thể trên luồng chính – bạn có thể cải thiện khả năng phản hồi đối với hoạt động đầu vào của người dùng bằng cách chia nhỏ các tác vụ dài.

Lưu ý đến tình trạng trùng lặp hoạt động tương tác

Một phần đặc biệt khó khăn khi tối ưu hoá INP là khi bạn có các lượt tương tác trùng lặp. Chồng chéo tương tác có nghĩa là sau khi tương tác với một phần tử, bạn thực hiện tương tác khác với trang trước khi tương tác ban đầu có cơ hội hiển thị khung tiếp theo.

Hình ảnh mô tả thời điểm các việc cần làm có thể trùng lặp, khiến thông tin đầu vào bị chậm trễ. Trong mô tả này, một lượt tương tác lượt nhấp trùng lặp với một lượt tương tác nhấn phím tắt để tăng độ trễ đầu vào cho lượt tương tác nhấn phím.
Hình ảnh trực quan hai hoạt động tương tác đồng thời trong trình phân tích hiệu suất trong Công cụ cho nhà phát triển của Chrome. Công việc hiển thị trong lượt tương tác lần nhấp đầu tiên gây ra độ trễ đầu vào cho hoạt động tương tác với bàn phím tiếp theo.

Các nguồn trùng lặp tương tác có thể đơn giản như việc người dùng thực hiện nhiều lượt tương tác trong một khoảng thời gian ngắn. Điều này có thể xảy ra khi người dùng nhập vào các trường trong biểu mẫu, nơi nhiều lượt tương tác với bàn phím có thể diễn ra trong một khoảng thời gian rất ngắn. Nếu tác vụ trên một sự kiện chính đặc biệt tốn kém (chẳng hạn như trong trường hợp phổ biến của các trường tự động hoàn thành, trong đó yêu cầu mạng được gửi đến phần phụ trợ), bạn có một số lựa chọn:

  • Hãy cân nhắc việc huỷ bỏ dữ liệu đầu vào để giới hạn số lần một lệnh gọi lại sự kiện thực thi trong một khoảng thời gian nhất định.
  • Sử dụng AbortController để huỷ các yêu cầu fetch gửi đi, nhờ đó, luồng chính sẽ không bị tắc nghẽn khi xử lý các lệnh gọi lại fetch. Lưu ý: bạn cũng có thể dùng thuộc tính signal của thực thể AbortController để huỷ sự kiện.

Một nguồn khác làm tăng độ trễ đầu vào do các hoạt động tương tác chồng chéo có thể là các ảnh động tốn kém. Cụ thể, ảnh động trong JavaScript có thể kích hoạt nhiều lệnh gọi requestAnimationFrame, có thể cản trở người dùng tương tác. Để giải quyết vấn đề này, hãy sử dụng ảnh động CSS bất cứ khi nào có thể để tránh xếp hàng các khung ảnh động có thể tốn nhiều tài nguyên. Tuy nhiên, nếu làm việc này, hãy nhớ tránh các ảnh động không được kết hợp để ảnh động chạy chủ yếu trên GPU và luồng của trình tổng hợp, chứ không phải trên luồng chính.

Kết luận

Mặc dù độ trễ đầu vào có thể không chiếm phần lớn thời gian cần để chạy các lượt tương tác, nhưng điều quan trọng là bạn cần hiểu rằng mọi phần của lượt tương tác đều chiếm một khoảng thời gian mà bạn có thể giảm bớt. Nếu nhận thấy độ trễ nhập dài, thì bạn có cơ hội để giảm độ trễ này. Việc tránh các lệnh gọi lại bộ tính giờ định kỳ, chia nhỏ tác vụ dài và nhận biết được sự trùng lặp tương tác tiềm ẩn đều có thể giúp bạn giảm độ trễ đầu vào, giúp người dùng trang web của bạn tương tác nhanh hơn.

Ảnh chính từ Unsplash của Erik Mclean.