Callback - từ javascript tới C#

Lâu rồi không viết blog. Một ngày có quá nhiều thứ để làm, trong khi thời gian thì lúc nào cũng chỉ có bấy nhiêu. Chợt thấy vô vị nếu như ngày qua ngày cắm đầu vào công việc, mà công việc thì càng cắm càng sâu, không còn một chút gì gọi là thú vui. Thôi thì từ giờ dù có bận tới đâu cũng dành ra 1h để viết bài, coi như là giải trí và cũng đáp ứng nhu cầu của các bạn đọc kỳ vọng.

Trong bài viết lần này, mình sẽ hướng dẫn về callback (gọi lại) trong 2 ngôn ngữ là javascript và c#.

Callback là gì?

Callback là khái niệm để chỉ 1 hành động (A) được gọi sau khi thực hiện 1 hành đồng (B) mà không biết trước thời điểm kết thúc của (B).

Ví dụ

  • Ê mày! khi nào học xong (B) thì gọi tao dậy (A) nhen.
  • Anh sẽ gọi cho em (B) khi về tới nơi (A)
  • Alert (B) khi load xong dữ liệu (A)
  • ajax success/error callback

javascript callback

Callback trong js đơn giản vì js có thể truyền tên của function như là 1 tham số. Và toán tử invoke '()' sẽ thực hiện function đó.

Trên đây là 1 ví dụ đơn giản về callback. Ở đây mình đã viết theo dạng anonymous function, tất nhiên truyền vào 1 hàm cũng hợp lệ

Truyền tham số cho callback cũng hết sức đơn giản

javascript callback

jquery ajax callback

Thì nó cũng chỉ là javascript callback thôi chứ không có gì to lớn. Ví dụ như sau:

Như ví dụ ở phần javascript callback, ở đây mình gọi hành động success bằng 1 function được định nghĩa và error bằng 1 anonymous function. Tham số truyền vào callback function cũng tương tự như js.

c# callback

Trong C# bạn không thể truyền tên hàm như là 1 tham số, do đó mình phải sử dụng 1 kỹ thuật mới, đó là delegate.

Có thể bạn đã đọc nhiều bài viết về delegate, rồi delegate tương tự con trỏ hàm trong C++... OK, tôi không giỏi C++, tôi không biết con trỏ hàm gì hết. Bạn đừng lôi mấy thứ đó vào cho khó hiểu. Hãy đơn giản: Tôi không làm được việc đó, tôi delegate (ủy quyền/nhờ) anh làm giùm tôi.

Vậy thì callback trong C# chính là nhờ delegate invoke thay vì tự invoke như javascript. Hãy xem xét chương trình sau và mình sẽ đi lần lượt 1 cách cụ thể

01. định nghĩa 1 delegate

public delegate void Callback();

Trong đó, void là kiểu của phương thức mà delegate này sẽ trỏ bọc lấy. Nếu phương thức có tham số thì định nghĩa thêm tham số cho delegate

public delegate void Callback(int result);

02. định nghĩa phương thức dùng để invoke

Với khuôn mẫu delegate đã được định nghĩa, phương thức này sẽ là phương thức có kiểu trả về là void và không có tham số đầu vào

public void DoCallback() {}

Thực tế bạn có thể làm ngược lại 2 bước này. Tức là dựa vào 1 method có sẵn để tạo ra delegate, như vậy sẽ dễ dàng hơn.

03. tạo 1 đối tượng delegate

Callback callback = new Callback(DoCallback); // Callback callback = DoCallBack;

Khi tạo 1 delegate, nếu muốn invoke method nào thì truyền method ấy vào hàm khởi tạo của delegate. Hoặc đơn giản hơn nữa, bạn gán method cần invoke cho delegate đó

04. truyền delegate vào method

Yeah, vì không cho truyền tên hàm như javascript nên đây là cách mà C# truyền, đơn giản nó là 1 tham số của hàm

static void DoWork(int e, Callback callback) {}

Và mấu chốt của vấn đề chính là invoke delegate, hay nói cách khác chính là thực thi phương thức mà delegate này chỉ tới

callback.Invoke(); // callback();

Trong trường hợp method thực thi có tham số, bạn chỉ cần truyền tham số vào hàm invoke của delegate

callback.Invoke(5); // callback(5);

05. cuối cùng, do your work

DoWork(1, callback);

Kết quả trong trường hợp có tham số

c# delegate callback

action - Anonymous delegate

Tương tự như javascript có anonymous function, C# có anonymous delegate. Đó chính là Action.

Với action, bạn không cần định nghĩa phương thức cho delegate (vì nó nặc danh mà)

DoWork(1, () => { Console.WriteLine("I am a callback by action"); });

Đơn giản phải không, action được viết bằng cú pháp lambda không có tham số như sau:

() => { /*do something here*/ }

Nếu có tham số truyền vào, cũng không có gì khó khăn

(int i) => { Console.WriteLine("i = " + i); }

Vậy thì DoWork với tham số sẽ đơn giản như sau

DoWork(1, (int e) => { Console.WriteLine(e); });

Áp dụng

Dĩ nhiên là trong Console App thì chả có gì cần thiết phải áp dụng callback. Nhưng trong các desktop application với sự kiện, delegate callback tỏ ra vô cùng hữu dụng. Ví dụ như load dữ liệu từ database trong thread, callback sau khi update thông tin...bằng cách ứng dụng 1 cách linh hoạt delegate, bạn có thể làm chủ khá nhiều thứ (+events) và tạo cho ứng dụng của mình vô cùng mượt mà và uyển chuyển.

Comments

  1. Một kiến thức đơn giản mà viết quá phức tạp. Đưa ví dụ và so sánh linh tinh. Cái ví dụ không nói lên được dùng callback khi nào. Rồi lấy cái ví dụ ajax làm ví dụ mà không nói dc callback của ajax được thực thi khi nào, nó có thật sự là callback hay không? .v.v.

    ReplyDelete
    Replies
    1. :v hân hạnh

      Tất nhiên không ai nhảy xuống nước là biết bơi, không ai không trải qua 1 quá trình dài để có thể giỏi được.

      Những bài viết của mình ngoài mục đích chia sẻ (kinh nghiệm bản thân) còn có mục đích ghi nhớ, và học hỏi từ những chia sẻ của người khác (ví dụ như comment của bạn) để biết mình còn thiếu sót những gì, cần sửa chữa những gì.

      Cảm ơn ý kiến đóng góp của bạn, mình sẽ cố gắng viết chi tiết trong những bài viết khác.

      Delete
  2. Hay lắm bạn. Mình ko phải dân IT lại tự học lập trình nên đọc nhiều bài giải thích về cái này nhưng cứ mơ hồ không hiểu. Đọc xong bài này mình đã ngộ được thế nào là callback hay delegate.
    Cảm ơn bạn!

    ReplyDelete
  3. Hi, bạn có thể làm một ví dụ về cái này không? Ví dụ như load dữ liệu từ database trong thread, callback sau khi update thông tin...

    ReplyDelete
  4. thấy rất rõ ràng , dễ hiểu. Thanks

    ReplyDelete
  5. Bài viết rõ ràng, dễ hiểu. Cảm ơn Quang!

    ReplyDelete
  6. Dễ hiểu, thích cái ví dụ về cách tạo callback bạn đưa ra.

    ReplyDelete
  7. Dễ hiểu, thích cái ví dụ về cách tạo callback bạn đưa ra.

    ReplyDelete

Post a Comment

Popular posts from this blog

Gỡ bộ Visual Studio ra khỏi máy tính

Căn giữa thẻ div trong thẻ div