debounce, throttle và once – ba hàm thêm cách giải quyết logic người dùng!
Bài viết được sự cho phép của tác giả Tống Xuân Hoài
Vấn đề
Tìm ra cách giải quyết vấn đề là một trong những kỹ năng hết sức quan trọng đối với lập trình viên. Thông thường, khi chúng ta làm càng nhiều thì kinh nghiệm càng lên cao. Lúc này đối mặt với những bài toán tương tự mà có thể nhanh chóng tìm ra hướng giải quyết.
Có nhiều cách để học hỏi kinh nghiệm, một trong số đó là chịu khó tìm kiếm và đọc nhiều bài viết, tài liệu trên mạng. Nhiều khi kiến thức ta thu nạp được chưa cần thiết ngay lúc này, nhưng đến một lúc nào đó nó có thể phát huy tác dụng. Hoặc ít ra, đọc để trong đầu ta tự thốt lên: “À hóa ra với trường hợp này thì chúng ta nên xử lý thế này…”.
debonce
, throttle
và once
là ba hàm tiện ích mà qua đó có thể ứng dụng trong rất nhiều trường hợp. Đặc biệt là logic về UI/UX, trải nghiệm người dùng… Bài viết ngày hôm nay, tôi xin phép được trình bày về công dụng cũng như cách sử dụng chúng.
Debounce
Debounce là một kỹ thuật ngăn chặn một chuỗi sự kiện tương tự nhau diễn ra liên tiếp. Thay vào đó, sự kiện tiếp theo chỉ được gọi sau một khoảng thời gian hành động chấm dứt.
Một ví dụ thông dụng nhất mà chúng ta thường gặp đó là tính năng gõ từ khóa vào ô tìm kiếm. Khi nhập kí tự, kết quả tìm kiếm hoặc cụm từ gợi ý hiện ra. Đằng sau quá trình này là một cách xử lý nào đó, ví dụ như gọi API để lấy dữ liệu trước khi người dùng bấm vào nút tìm kiếm hoặc nhấn Enter. Nếu bắt sự kiện keypress
thì cứ mỗi lần nhấn phím sẽ gọi một lần API. Như thế quả là lãng phí tài nguyên máy chủ bời vì tốc độ của người gõ là rất nhanh, chưa kể từ khóa họ nhập vào còn chưa đầy đủ. Để xử lý tối ưu trong trường hợp này là chờ một khoảng thời gian người dùng không nhấn nhím nữa thì hãy kích hoạt cuộc gọi API.
Đây là lúc debounce
phát huy tác dụng. Một hàm debounce
có thể trông giống như dưới đây:
function debounce(func, delay) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
}
Sau đó, sử dụng hàm trong sự kiện keypress
. Ở đây mình lấy ví dụ trong vue:
<input @keypress="debounce(triggerCallAPI, 500)" />
Khi đó cứ mỗi 500ms mà người dùng không nhập gì nữa thì triggerCallAPI
sẽ được gọi.
Một trường hợp phổ biến khác là sự kiện resize
của trình duyệt. Trong quá trình thay đổi kích thước cửa sổ, có nhiều hàm cần chạy để xử lý logic. Nếu cứ gọi hàm liên tục khi resize
chắc chắn hiệu năng sẽ bị ảnh hưởng. Lúc đó, chúng ta có thể sử dụng debounce
để giải quyết vấn đề này.
Xem thêm việc làm CSS lương cao trên TopDev
Throttle
Throttle phần nào giống như Debounce. Nghĩa là nó cũng ngăn chặn sự kiện diễn ra liên tiếp, nhưng theo một cách khác so với Debounce.
Nếu Debounce chỉ kích hoạt sự kiện sau một khoảng thời gian mà sự kiện không xảy ra nữa thì Throttle lại chỉ kích hoạt sự kiện sau một khoảng thời gian mà bất kể sự kiện đó có diễn ra hay không. Hay nói ngắn gọn lại là Throttle chỉ cho phép chạy một sự kiện trong mỗi x giây. Sau x giây, lần chạy tiếp theo mới được thực thi nếu nó còn được kích hoạt (trigger).
Một hàm throttle
có thể trông giống như dưới đây:
function throttle(func, delay) {
let wait = false;
return (...args) => {
if (wait) {
return;
}
func(...args);
wait = true;
setTimeout(() => {
wait = false;
}, delay);
}
}
Bất cứ khi nào cần giới hạn thời gian giữa các lần kích hoạt sự kiện bạn có thể áp dụng Throttle. Ví dụ, ngăn chặn người dùng bấm quá nhanh vào một nút “Submit”.
<input type="submit" @submit="throttle(triggerCallAPI, 500)" />
Nghĩa là triggerCallAPI
chỉ được gọi sau mỗi 500ms bất kể người dùng có bấm vào nút bao nhiêu lần đi chăng nữa.
Once
Once chỉ cho phép sự kiện được gọi một lần duy nhất. Once hữu ích trong trường hợp bạn chỉ cho phép người dùng thực hiện một hành động trong phiên truy cập.
Một hàm once
có thể giống giống như sau:
function once(func) {
let ran = false;
let result;
return function() {
if (ran) return result;
result = func.apply(this, arguments);
ran = true;
return result;
};
}
Ví dụ sử dụng trong trường hợp nút “Đánh dấu tất cả là đã đọc” của khung thông báo. Người dùng chỉ cần thực hiện bấm vào nút đó một lần trong mỗi phiên.
<button @click="once(triggerCallAPI)">Đánh dấu tất cả là đã đọc</button>
triggerCallAPI
chỉ được gọi một lần duy nhất khi người dùng bấm vào button. Các lần tiếp theo, triggerCallAPI
sẽ không được kích hoạt.
Tổng kết
Trên đây là 3 hàm debounce
, throttle
và once
với mô tả kèm theo cách sử dụng. Chúng rất thông dụng trong xử lý logic về giao diện người dùng, đến nỗi nhiều thư viện tiện ích đều có mặt của 3 hàm này như là lodash. Việc biết đến cũng như biết cách sử dụng có thể giúp bạn giảm được thời gian giải quyết vấn đề trong những trường hợp tương tự trong bài viết.
Bài viết gốc được đăng tải tại 2coffee.dev
- Responsive giao diện cực đỉnh với Container Queries
- VisGrid – Thiết lập Selenium-Grid qua giao diện
- Đợi đối tượng UI hoặc sự kiện với Selenium WebDriver
Xem thêm Việc làm IT hấp dẫn trên TopDev
- M Mới ra trường không kinh nghiệm, sao làm BA?
- C Chuyển đổi SA key sang Workload Identity
- U Use Case Diagram và 5 sai lầm thường gặp
- K Kinh nghiệm xử lý câu lệnh điều kiện trong JavaScript
- D Dart là gì? Ứng dụng của ngôn ngữ lập trình Dart
- C Chuẩn Hóa CV, Nhận Ngay Phím Chất
- S So sánh MySQL và MongoDB: Nên chọn CSDL nào?
- D Dân BA có cần phải rành về kỹ thuật???
- C CSS Selector là gì? Cách sử dụng các loại CSS Selector phổ biến
- P Phân biệt Sketch, Wireframe, Mockup, và Prototype?