JavaScript - Debounce Function là gì?
Javascript
246
UX
16
White

Võ Hoài Nam viết ngày 02/11/2015

Trong một bài test của mình, có một câu là hãy thực hiện Instant Search giống của Twitter. Cách sử dụng là khi bạn nhập một ký tự thì sẽ gởi một request lên Server để lấy dữ liệu.

alt text

Vấn đề đặt ra

var txtKeyword = $('#key-word'),
    lstResult = $('#result'),
    keyword = txtKeyword.val();

$.ajax(function() {
  method: 'GET',
  url: 'http://example.com/getdata',
  data: {
    keyword: keyword
  }
}).done(function(data) {
  var people = JSON.parse(data),
      html = '';

  people.forEach(function(person) {
    html += '<li>' + person.name + '</li>';
  });

  lstResult.empty();
  lstResult.append(html);
});

Bạn viết đoạn code như trên. Khi bạn nhập "abc" thì sẽ có 3 request được gởi đi lần lượt cho "a", "ab""abc". Giả sử, thứ tự dữ liệu được trả về lần lượt là "a", "abc""ab". Có gì đó sai sai ở đây?

alt text

Trong khi đó, kết quả bạn cần là "abc" chứ không phải là "ab". Như vậy, lỗi này sẽ ảnh hưởng tới UX (User Experience). Để giải quyết vấn đề đó sẽ có rất nhiều cách. Mình tin là có bác sẽ nghĩ tới chuyện chờ người dùng nhập xong khoảng độ 1 giây, rồi lấy kết quả cuối cùng đem đi gởi. Vậy làm sao để biết nó khi nào nhập xong ta? Lúc đó thì ta sẽ sử dụng một kỹ thuật có tên là Debounce.

Debounce Function

Đầu tiên, bạn sẽ muốn gọi hàm debounce(func, wait), truyền vào hàm cần thực thi và thời gian delay. Do đó, bạn sẽ viết hàm debounce sẽ trả về một hàm anonymous.

function debounce(func, wait) {
  return function() {
    // TODO
  }
}

Sau đó, bạn sẽ cần lấy giá trị của các tham số truyền vào.

function debounce(func, wait) {
  return function() {
    var context = this,
        args = arguments;
  }
}

Tiếp theo là bạn tạo một hàm tên là executeFunction để khi gọi hàm này, thì hàm được truyền vào sẽ thực thi.

function debounce(func, wait) {
  return function() {
    var context = this,
        args = arguments;

    var executeFunction = function() {
      func.apply(context, args);
    }
  }
}

Bây giờ, ta gọi hàm setTimeout để delay việc thực thi mỗi khi gọi hàmdebounce tương ứng với wait giây.

function debounce(func, wait) {
  return function() {
    var context = this,
        args = arguments;

    var executeFunction = function() {
      func.apply(context, args);
    }

    setTimeout(executeFunction, wait);
  }
}

Quay lại với giải pháp đã đưa ra, đoạn code tới đây đã giải quyết được vấn đề mỗi khi người dùng nhập thì delay một khoảng thời gian mới thực thi hàm. Nhưng có gì đó sai sai! Hình như là nó chưa lấy được giá trị cuối cùng của người dùng sau khi nhập rồi mới gởi request. Ta chỉ cần xóa đi các lần gọi hàm trước đó là được chứ gì, dùng hàm clearTimeout.

function debounce(func, wait) {
  var timeout;

  return function() {
    var context = this,
        args = arguments;

    var executeFunction = function() {
      func.apply(context, args);
    };

    clearTimeout(timeout);
    timeout = setTimeout(executeFunction, wait);
  };
};

Như vậy là đã viết xong hàm debounce. Để sử dụng thì ta viết như sau.

// Usage
var handleClick = debounce(function (e) {
  // do stuff here
  console.log(e);
}, 500);

$('button').on('click', handleClick);

Chuyện bên lề

Trên blog của YinYangIT có đề cập tới một chiêu thức khác đó là requestAnimationFrame() thay thế cho setTimeout(). Bạn thậm chí có thể không cần đến tham số wait khi sử dụng phương pháp này. Nếu bạn nào có thời gian nghiên cứu thì tìm hiểu thêm.

Hàm debounce đã được một số thư viện hỗ trợ như là Underscore.js, Lodash. Thực ra, đoạn code được dùng demo là của Underscore phiên bản cũ. Cá nhân thì thấy nếu bạn có nhu cầu tìm hiểu các kỹ thuật khi làm việc với JavaScript, nên đọc mã nguồn của Underscore.js và nên đọc toàn bộ mã nguồn đã release để hiểu được rõ ràng vấn đề hơn.

Blog: JavaScript - Debounce Function là gì?

Tham khảo

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Võ Hoài Nam

6 bài viết.
37 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
34 7
"Quy tắc ngón tay cái" mà mình đề cập trong bài viết này chính là thói quen sử dụng ngón tay cái trên mobile. Viết rõ ràng như vậy để tránh mấy bài...
Võ Hoài Nam viết hơn 2 năm trước
34 7
White
12 6
Sẵn dịp đọc cuốn (Link) nên mình lược dịch và thêm thắt một số chỗ để có thêm tài liệu tham khảo bằng tiếng Việt. Mình sẽ chia cuốn sách ra làm nhi...
Võ Hoài Nam viết hơn 2 năm trước
12 6
White
5 1
Lời người dịch Tiếp tục loạt bài lược dịch của cuốn "The Guide to Wireframeing". Ở phần này có một số mình không tìm được nghĩa tiếng Việt tương ...
Võ Hoài Nam viết 1 ngày trước
5 1
Bài viết liên quan
White
43 8
Tăng sức mạnh cho javascript với lodash Lần này mình sẽ giới thiệu 1 thư viện javascript vô cùng bá đạo có tên là "lodash]1]", có thể nói nó là LI...
Huy Hoàng Phạm viết hơn 2 năm trước
43 8
White
2 0
11. Sử dụng hình ảnh để thu hút sự chú ý của khách truy cập (Ảnh) Người dùng là trực quan Các trang web đã sử dụng hình ảnh đẹp được chọn để làm ...
Đào Mạnh Thắng viết gần 2 năm trước
2 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
6 bài viết.
37 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!