Cơ chế bất đồng bộ trong javascript

Trước khi bắt đầu đi vào tìm hiểu cơ chế hoạt động bất đồng bộ (async) trong javascript chúng ta xét ví dụ sau:

Đây là đoạn code cơ bản trong javascript để in ra một string và chắc hẳn nhìn vào nó bạn cũng đoán ra kết quả đầu ra như thế nào:

Nhìn vào đoạn code này ta thấy nó hoạt động giống như cơ chế đồng bộ nghĩa là sẽ thực thi từng dòng lệnh một, tuy nhiên khi ta sửa đổi lại đoạn code một chút như sau:

Kết quả chạy đoạn code:

Qua ví dụ trên ta có thể thấy rằng thay vì chờ đợi phần code nằm trong setTimeout() thực hiện xong thì lệnh console.log() cuối cùng mới thực hiện giống như cơ chế chạy đồng bộ trong các khác thì lệnh console.log() lại trả về kết quả trước khi đoạn code nằm trong setTimeout() trả về kết quả. Đây chính là điểm khác nhau giữa cơ chế bất đồng bộ và đồng bộ trong việc lập trình. Việc xử lý bất đồng bộ trong javascript được mô tả dựa trên các thành phân như sau:

Trước khi bước vào tìm hiểu cách hoạt động của các thành phần trên, chúng ta sẽ điểm qua khái niệm về mỗi thành phần.

  • CALL STACK - là một dạng cấu trúc dữ liệu ghi lại vị trí các lệnh đang được thực hiện trong chương trình. Khi lệnh bắt đầu được thực hiện sẽ được đưa vào đỉnh của stack và sau khi thực hiện xong sẽ được lấy ra khỏi ngăn xếp.

  • WEB APIs - vể bản chất đây chính là các thread mà ta không thể truy cập trực tiếp mà chỉ có thể gọi được đến nó. Các thread này do trình duyệt cung cấp.

  • CALLBACK QUEUE - là một dạng cấu trúc dữ liệu với nguyên tắc First-In-First-Out (vào trước ra trước).

  • EVENT LOOP - có nhiệm vụ giám sát tình trạng của CALL STACK và CALLBACK QUEUE. Để hiểu được quá trình thực hiện của cơ chế bất đồng bộ ta sẽ đưa ví dụ thứ hai vào và thực hiện trong mô hình trên.

  • Đầu tiên khi chương trình bắt đầu chạy lệnh đầu tiên của chương trình (console.log('This is the first line')) sẽ được đưa vào trong CALL STACK.

  • Lệnh này lập tức trả về dòng chữ This is the first line đồng nghĩa với việc nó đã chạy xong và được đẩy ra khỏi CALL STACK.

  • Tiếp đến hàm setTimeout(function() { console.log('This is the second line'); }, 1000); được đưa vào trong CALL STACK để thực hiện.

  • Tuy nhiên hàm nay không trả về kết qua ngay mà phải đợi 1 giây. Hàm setTimeout() ở đây chính là một API mà WEB APIs cung cấp. Lập tức đoạn code này được chuyển vào trong WEB APIs và trình duyệt sẽ tạo ra một bộ hẹn giờ tương ứng với thời gian trên là 1 giây trước khi trả về kết quả

  • Khi đoạn code thứ 2 được chuyển sang WEB APIs thì lập tức đoạn code cuối cùng console.log('This is the last line ') đã được đưa vào CALL STACK để thực hiện và trả về kết quả là dòng chữ This is the last line. Sau đó đoạn code này cũng được đẩy ra khỏi CALL STACK


  • Sau khi bộ giờ trong WEB APIs chạy xong thì kết quả trả về lúc này không được in ngay ra màn hình mà nó được đẩy vào CALLBACK QUEUE

  • EVENT LOOP với chức năng liên tục giám sát xem CALL STACK đã trống chưa và CALLBACK QUEUE có gì không. Lúc này CALLBACK QUEUE đang chư kết quả mà WEB APIs trả về nên và CALL STACK lúc này cũng đã trống do toàn bộ code trong chương trình đã được thực hiện nên nó sẽ đẩy kết quả trong CALLBACK QUEUE vào lại CALL STACK và đoạn code console.log(''This is the second line) được thực hiện và trả kết quả ra màn hình.

Đó là toàn bộ quá trình diễn ra trong cơ chế chạy bất đồng bộ của javascript, tuy nhiên ta cần chú ý một số điểm sau:

  • EVENT LOOP chỉ tiến hành đẩy hàm trả về từ CALLBACK QUEUE sang CALL STACK khi CALL STACK đã thực hiện xong hết các đoạn code khác của chương trình
  • Thứ tự các kết quả được trả về từ WEB APIs sang CALLBACK QUEUE sẽ không theo thứ tự đưa vào mà sẽ tùy thuộc hàm nào chạy xong trước sẽ được đẩy vào CALLBACK QUEUE trước đồng nghĩa với việc sẽ được chuyển qua CALL STACK trước.

Qua bài viết này mong mọi người phần nào hiểu được cơ bản về cách thức hoạt động của cơ chế bât đồng bộ trong javascript để áp dụng nó trong công việc hằng ngày.