debounce, throttle và once - ba hàm thêm cách giải quyết logic người dùng!

debounce, throttle và once - ba hàm thêm cách giải quyết logic người dùng!

Tin ngắn hàng ngày dành cho bạn
  • Rust sinh ra để tái định nghĩa nhiều thứ. Trong đó chắc phải kể đến JavaScript. Từ đầu năm đến giờ các công cụ làm từ Rust mà để cho JavaScript dùng đếm sương sương cũng vài ba cái rồi. Mới đây nhất là Oxc.

    Oxc là một công cụ phân tích cú pháp (parser), kiểm tra lỗi (lint), định dạng (formatter), chuyển đổi (transformer), minifier... tất cả đều được viết bằng Rust, trong một công cụ duy nhất.

    Mặc dù vẫn đang trong quá trình xây dựng nhưng thử nhìn điểm hiệu năng của nó so với swc hoặc eslint mà xem 🫣

    » Xem thêm
  • Mấy hôm nay, à mà cũng không hẳn, do sự kiện WWDC vừa rồi nên Apple lại bị dân cư mạng mang ra bàn tán rằng rốt cục thì các tính năng AI của họ đang ở đâu? Trong khi các hãng khác đang lao mình vào việc mang AI lên thiết bị, phần mềm của họ thì Apple lại đang có vẻ... không quan tâm lắm.

    Thậm chí mới đây các nhà nghiên cứu của Apple cho rằng các mô hình LLM sẽ "sụp đổ hoàn toàn về độ chính xác" khi được đưa ra các vấn đề cực kỳ phức tạp. Chỉ ra rằng suy luận chỉ là huyễn hoặc thì ngay lập tức đã có nhiều bài phản bác nghiên cứu này. Một lần nữa cho thấy rằng Apple đang suy nghĩ điều gì với AI trên thiết bị của họ?

    Mình thì nghĩ đơn giản thôi, Apple có vẻ đang gặp khó khăn với việc tạo ra AI cho riêng họ. Tức là khó khăn ngay từ đoạn thu thập dữ liệu để đào tạo rồi. Họ luôn tỏ ra tôn trọng quyền riêng tư của người dùng nên chẳng lẽ lại lên mạng đi xào nấu dữ liệu ở khắp nơi, hoặc "chôm" dữ liệu dưới máy người dùng lên? Chắc chắn, họ cũng không muốn cung cấp thêm dữ liệu người dùng cho các bên thứ 3 như OpenAI.

    Nhưng nhờ những khó khăn này biết đâu họ lại tìm ra được hướng đi mới. Ai cũng chọn phần dễ thì gian khổ để phần cho ai 😁. À mình không phải là "fan" của Apple, chỉ là thấy cái nào phù hợp thì dùng thôi 🤓

    » Xem thêm
  • Người "nhạy cảm" với markdown đó là khi thấy một thư viện tạo khung soạn thảo mới là nhảy ngay vào xem nó có gì mới. Milkdown/milkdown là một ví dụ.

    Xem thử thì thấy ổn phết mọi người ạ. Vài nữa thử tích hợp vào opennotas xem sao. Mang tiếng là ứng dụng ghi chú hỗ trợ markdown cơ mà cái thư viện tiptap nó không chịu làm thêm phần hỗ trợ markdown 😩. Dùng thư viện ngoài thì vẫn chưa ngon cho lắm.

    » Xem thêm

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, throttleonce 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.

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, throttleonce 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.

Tài liệu tham khảo:

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...