Javascript cơ bản

Bất đồng bộ trong Javascript – Callback

Javascript là ngôn ngữ single-thread, tức là nó chỉ chạy trên một luồng duy nhất. Nếu xử lý theo cơ chế đồng bộ (synchonous) thì khi thực hiện các công việc như thao tác với database, gọi request đến server… thì ứng dụng sẽ phải bỏ ra một khoảng thời gian khá dài để chờ cho những công việc ở trên thực thiện xong rồi mới bắt tay vào thực hiện công việc tiếp theo, điều đó sẽ làm tiêu tốn một khoản thời gian không nhỏ ảnh, hưởng đến trải nghiệm người dùng hoặc trong trường hợp xấu có thể dẫn đến … treo ứng dụng.

I. Đồng bộ và bất đồng bộ

1. Xử lý đồng bộ (Synchronous/Sync)

Khi xử lý đồng bộ, chương trình sẽ chạy theo từng bước và chỉ khi nào bước 1 được thực hiện xong thì mới bắt đầu chuyển sang thực hiện bước 2. Một trong những nguyên tắc cơ bản trong lập trình áp dụng quy tắc này chính là biên dịch. Khi biên dịch, trình biên dịch sẽ thực hiện dịch lần lượt theo thứ tự từ trái qua phải, từ trên xuống dưới, khi nào dịch xong dòng trên thì mới dịch xuống dòng dưới, điều này sẽ sinh ra một trạng thái được gọi là trạng thái chờ

Ưu điểm:

Vì chạy tuần tự theo đúng nguyên tắc nên sẽ hạn chế mắc phải các lỗi liên quan đến quá trình.
Nếu bị lỗi thì sẽ dễ dàng tìm ra và khắc phục, dễ quản lý.

Nhược điểm:

Vì chạy theo thứ tự và phải chờ đợi nhau nên sẽ sinh ra trạng thái chờ, sẽ có những câu lệnh cần phải thao tác với dữ liệu bên ngoài vì thế nó cần một khoảng thời gian để lấy dữ liệu về trước khi xử lý nên gây mất thời gian, ảnh hưởng đến trải nghiệm người dùng

2. Xử lý bất đồng bộ (Asynchronous /Async)

Xử lý bất đồng bộ cho phép chương trình nhảy một số bước nào đó để thực hiện một số đoạn mã nhất định. Nếu công việc thứ hai kết thúc trước, nó có thể sẽ cho ra kết quả trước cả công việc thứ nhất.

Ví dụ về việc nấu ăn: thay vì đợi cơm chín rồi mới nấu thức ăn, bạn nấu cơm và đặt thời gian (callback) rồi sau đó quay sang nấu thức ăn

Ưu điểm:

Với bất đồng bộ, nhiều công việc có thể thực hiện cùng lúc mà không phải chờ đợi nhau, giảm thiểu được thời gian xử lý vì đã giảm thiểu được thời gian chờ đợi một task nào đó hoàn thành.

Nhược điểm:

  • Khó kiểm soát
  • Một thao tác thêm dữ liệu phải thông qua hai công đoạn là validate dữ liệu và thêm dữ liệu, nếu thao tác validate xảy ra sau thao tác thêm thì còn gì tệ hại hơn nữa

II. Callback (ES5)

Callback là giải pháp đầu tiên được đưa ra của ES5 để giải quyết các vấn đề liên quan đến xử lý bất đồng bộ theo đúng trình tự mong muốn

callback là truyền một đoạn code (hàm A) vào trong một đoạn code khác (hàm B) dưới dạng đối số. Tới một thời điểm nào đó, hàm A sẽ được hàm B gọi lại (callback)

Ví dụ về chưa sử dụng callback

// Con mèo cần 5s để ướng nước
function uong_nuoc () {
   setTimeout (() => {
      console.log('Uống nước');
   },5000)
}
// Con mèo ăn cơm
function an_com () {
   console.log('Ăn cơm');
}

//Gọi hàm
uong_nuoc();
an_com();

Kết quả

Ăn cơm

Uống ước

Có thể thấy an_com() chạy trước mặc dù gọi sau, 5s sau uong_nuoc() mới được gọi
Ví dụ khi sử dụng callback
function uong_nuoc (sen) {
   setTimeout (() => {
      console.log('Uống nước');
      sen(); // Lúc sen nhận ra là mèo đã uống nước xong
   },5000)
}
function an_com () {
   console.log('Ăn cơm');
}
// sen đứng cạnh mèo, uống nước xong mới đưa khay cơm
const sen = function() {
   an_com_1();
}
// Thực thi callback
uong_nuoc_1(sen);

Đoạn code trên có thể viết ngắn gọn lại như sau
function uong_nuoc (sen) {
   setTimeout (() => {
      console.log('Uống nước');
      sen(); // Lúc sen nhận ra là mèo đã uống nước xong
   },5000)
}
function an_com () {
   console.log('Ăn cơm');
}
uong_nuoc(() => {
   an_com();
});
Kết quả
Uống nước
Ăn cơm

Ưu điểm:

  • Callback là một mô hình khá phổ biến nên rất dễ hiểu
  • Rất dễ implement trong các function của chúng ta

Nhược điểm:

Về cơ bản thì callback có thể giải quyết được vấn để xử lý bất đồng bộ trong javascript, tuy nhiên khi đưa vào áp dụng thực tế nó lại có khá nhiều vấn đề như:

  • Khi thao tác bất đồng bộ, các callback phải chờ nhau thực hiện dẫn đến tổng thời gian hoàn thành công việc bị kéo dài hơn.
  • Dài dòng, khó đọc, khó bảo trì.
  • Callback hell (pyramid of doom): là cách code không tối ưu dẫn đến việc có quá nhiều callback lồng nhau từ đó sẽ gay mất thời gian cho việc bảo trì cũng như fix bug. Đại khái callback hell có dạng giống như hình bên dưới.

Leave a Comment