Ajax

Callback

Hiện tại thì khi viết code cho bất kì target platform nào thì bạn cũng ít nhiều viết các callbacks, dù là bạn có để ý hay biết tới cái tên “callback” hay không. Nếu câu trả lời là không, thì bài viết này sẽ giúp các bạn có một số kiến thức để vận dụng các callbacks có sẵn trong quá trình viết code, cũng như tự tạo các callbacks của riêng bạn, để ứng dụng hoạt động tối ưu hơn, ít gây tình trạng “đứng hình” hơn.

callback

1. Callback là gì?

Như trong bài Asynchronous operation, tôi có giới hiệu tình huống “mời nước” và việc bạn chuẩn bị nước nôi ở một “background thread” là điều cần làm. Sau đó, bạn đem nước lên “UI thread” để mời mộc các vị khách – và đây, bạn đang thực hiện một callback.

Có thể dịch “callback” là “hàm gọi lại”. Nó là một method được định nghĩa tại một thời điểm này, được chương trình ghi nhớ phần NỘI DUNG định nghĩa của nó ngay tại thời điểm chạy qua nó, nhưng thời điểm để thực thi toàn bộ NỘI DUNG đó thì không nhất thiết phải là ngay tại thời điểm đó, mà có thể là 1 phút, 2 giờ, hoặc thậm chí là 69 năm sau khi chương trình chạy qua đoạn code đó để hiểu cái method đó có gì bên trong. Chẳng hạn, với Android, cái onClick(View view) callback “thần thánh” được gán nội dung ngay khi cái chương trình chạy qua View#setOnClickListener(…), nhưng việc thực thi toàn bộ mớ nội dung đó chỉ diễn ra khi bạn tương tác, cụ thể hơn là click, với View đó.

Bạn cho chạy đoạn code đó lên, và khi cái máy Android của bạn đọc qua nội dung hàm onClick(View) kia, nó sẽ tạm ghi nhớ nội dung của hàm, là một Toast. Tuy nhiên, nó không chạy cái nội dung đó ngay khi đọc qua, mà phải chờ tới khi người dùng click cái button đó thì mới Toast. Về mặt lí thuyết, ví dụ chương trình được khởi động tại thời điểm này, nhưng người dùng không click vào button ngay, mà chờ tới 69 năm sau mới click, thì cái máy của bạn cũng ráng ngồi chờ với người dùng kia chứ không “làm càng” mà chạy cái onClick bất kì lúc nào khác.

Như vậy, tóm lại, callback là tập hợp các method được định nghĩa và gán nội dung vào thời điểm hệ điều hành tiến hành nạp ứng dụng vào bộ nhớ RAM, nhưng sẽ được thực thi vào một thời điểm khác do lập trình viên chỉ định, có thể là sau một khoảng thời gian cố định, hoặc đi kèm với một event nào đó.

2. Tầm quan trọng của callback

Thực tế, các ứng dụng thực tế mà bạn tiếp xúc hàng ngày, kể cả ứng dụng web, đều có callback, thể hiện qua việc bạn nhấn vào một item nào đó rồi chương trình tiến hành thực hiện một hành động nào đó. Chẳng hạn như ví dụ bên trên, bạn nhấn vào Button thì xuất hiện Toast. Ngoài ra, các callbacks còn được sử dụng với các asynchronous operations, tức là sau khi operation kia đã hoàn thành thì nó sẽ thực hiện callback lên UI thread để thực thi các công việc tiếp theo. Chẳng hạn khi bạn xem phim trực tuyến, khi player đã tải được một lượng dữ liệu phim vừa đủ thì nó sẽ thực hiện một callback cho tự phát đoạn phim đó. Nếu không có callback, thì sau khi tải phim xong, bạn phải tự nhấn phím Play bằng tay để phát. Tóm lại, không có callback thì ứng dụng của bạn sẽ không hề có tính “tự động hóa” chút nào cả.

3. Không phải callback nào cũng mang tính asynchronous

Đôi lúc, bạn thao tác nhiều với asynchronous callbacks, bạn sẽ nghĩ là callback nào cũng là asynchronous, tức là nó sẽ được thực thi sau khi các method của UI thread chạy xong. Nhưng thực tế, trên Java, Javascript, Swift hay các ngôn ngữ khác, thì vẫn có synchronous callback, tức là mặc dù nó là callback, nhưng nội dung của nó sẽ được thực hiện trên UI thread luôn. Chẳng hạn, với Java, tôi có ví dụ sau:

Nội dung của method sortedInAccendingOrder(Integer[]) có chứa một callback. Nếu bạn cho cái Comparator callback trên là asynchronous, thì thứ nhất, method sortedInAccendingOrder sẽ return Integer[] numbers gốc luôn, hoạt động sắp xếp sẽ bị ngắt giữa chừng, và thứ hai là các phần tử được in ra theo thứ tự numbers ban đầu.

Nhưng không, cái Comparator bên trên là một synchronous callback, nghĩa là method sortedInAccendingOrder sẽ đợi cho Comparator#compare(Integer, Integer) chạy xong thì mới return cái numbers, và do đó, khi print các phần tử ra, thì chúng sẽ được sắp xếp theo thứ tự từ nhỏ tới lớn. Đó là -2, -1, 0, 3, 5. Callback ở đây sẽ được thực hiện ngay lập tức khi chương trình biên dịch đọc tới nó, và đợi tới khi hoàn tất thực thi nó xong thì hệ thống của bạn mới sang câu lệnh tiếp theo. Comparator#compare không phải là một asynchronous callback.

Đối với Javascript thì callback trong forEach cũng là một synchronous callback. Chẳng hạn:

“Done” sẽ được in ra sau các item, bởi callback trong forEach(callback) không phải là asynchronous. Nó sẽ được thực thi ngay trên UI thread và các methods khác sẽ phải xếp hàng chờ cho nó được thực thi xong thì mới tới chúng.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.