Bất đồng bộ

Frontend SELF VI
Mức độ , Bài học
Có sẵn

1.1 Các khái niệm cơ bản về bất đồng bộ

Bất đồng bộ trong JavaScript cho phép thực hiện các tác vụ ở chế độ nền mà không làm gián đoạn luồng thực thi chính. Điều này rất quan trọng cho các tác vụ có thể mất nhiều thời gian, chẳng hạn như yêu cầu mạng, đọc tệp và bộ đếm thời gian. Bây giờ chúng ta sẽ xem xét các khái niệm chính của lập trình bất đồng bộ trong JavaScript và đưa ra các ví dụ sử dụng.

JavaScript là ngôn ngữ đơn luồng

JavaScript là ngôn ngữ đơn luồng: điều này có nghĩa là nó thực hiện mã tuần tự trong một luồng duy nhất. Tuy nhiên, các hoạt động bất đồng bộ cho phép thực hiện các tác vụ ở chế độ nền, giải phóng luồng chính cho các tác vụ khác.

Event Loop

Event Loop là cơ chế quan trọng cho phép JavaScript xử lý các tác vụ bất đồng bộ. Event Loop quản lý hàng đợi thông điệp (Message Queue) và hàng đợi vi tác vụ (Microtask Queue), đảm bảo thực hiện các hoạt động bất đồng bộ.

  1. Hàng đợi thông điệp: chứa các tác vụ, chẳng hạn như xử lý sự kiện, yêu cầu mạng và bộ đếm thời gian. Các tác vụ từ hàng đợi này được thực hiện tuần tự.
  2. Hàng đợi vi tác vụ: chứa các tác vụ có ưu tiên cao hơn so với các tác vụ trong hàng đợi thông điệp. Ví dụ bao gồm hoàn thành promise và các cuộc gọi lại (callbacks) trong vi tác vụ.

Event Loop liên tục kiểm tra cả hai hàng đợi và thực hiện các tác vụ từ đó khi luồng chính trở nên trống.

Các hoạt động bất đồng bộ

Các hoạt động bất đồng bộ cho phép thực hiện các tác vụ ở chế độ nền. Các ví dụ chính về hoạt động bất đồng bộ bao gồm:

  • Bộ đếm thời gian (setTimeout, setInterval)
  • Xử lý sự kiện
  • Yêu cầu mạng (ví dụ, XMLHttpRequest, Fetch API)
  • Đọc/ghi tệp (trong Node.js)

Hãy cùng xem một vài ví dụ về hoạt động bất đồng bộ.

1.2 Bộ đếm thời gian

Bộ đếm thời gian cho phép thực hiện các tác vụ bị trì hoãn hoặc cách đều nhau theo khoảng thời gian.

Ví dụ sử dụng setTimeout

Trong ví dụ này, setTimeout thiết lập thực thi hàm sau 2 giây. Kết quả là, StartEnd được in ra trước, rồi sau 2 giây Executed after 2 seconds được in ra.

JavaScript
    
      console.log('Start');

      setTimeout(() => {
        console.log('Executed after 2 seconds');
      }, 2000);

      console.log('End');
    
  

Ví dụ sử dụng setInterval

Trong ví dụ này, setInterval thực hiện hàm mỗi giây, tăng dần counter và in ra giá trị của nó. Khi counter đạt 5, khoảng thời gian được xóa bằng cách sử dụng clearInterval:

JavaScript
    
      let counter = 0;

      const intervalID = setInterval(() => {
        counter++;
        console.log(`Counter: ${counter}`);
        if (counter >= 5) {
          clearInterval(intervalID);
        }
      }, 1000);
    
  

1.3 Xử lý sự kiện

Xử lý sự kiện cho phép thực hiện mã phản hồi lại hành động của người dùng hoặc các sự kiện khác.

Ví dụ sử dụng xử lý sự kiện

Trong ví dụ này, một bộ xử lý sự kiện click được thêm vào nút. Khi người dùng nhấp vào nút, thông báo Button clicked! được in ra:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Event Handler Example</title>
        </head>
        <body>
          <button id="myButton">Click me</button>

          <script>
            const button = document.getElementById('myButton');

            button.addEventListener('click', () => {
              console.log('Button clicked!');
            });
          </script>
        </body>
      </html>
    
  

1.4 Yêu cầu mạng

Yêu cầu mạng cho phép thực hiện các yêu cầu HTTP bất đồng bộ đến máy chủ.

Ví dụ sử dụng XMLHttpRequest

Trong ví dụ này, một yêu cầu GET bất đồng bộ được tạo ra đến một API, và khi yêu cầu hoàn thành, phản hồi được in ra trong console:

JavaScript
    
      const xhr = new XMLHttpRequest();
      xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);

      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          const response = JSON.parse(xhr.responseText);
          console.log(response);
        }
      };

      xhr.send();
    
  

1.5 Event Loop trong thực tế

Để hiểu rõ hơn về cách hoạt động của Event Loop, hãy xem xét ví dụ sau:

JavaScript
    
      console.log('Start');

      setTimeout(() => {
        console.log('Timeout 1');
      }, 0);

      Promise.resolve().then(() => {
        console.log('Promise 1');
      });

      setTimeout(() => {
        console.log('Timeout 2');
      }, 0);

      Promise.resolve().then(() => {
        console.log('Promise 2');
      });

      console.log('End');
    
  

Kết quả dự kiến sẽ là:

  • Start
  • End
  • Promise 1
  • Promise 2
  • Timeout 1
  • Timeout 2

Trong ví dụ này, đầu tiên các hoạt động đồng bộ được thực hiện (console.log('Start')console.log('End')). Sau đó các vi tác vụ được thực hiện (trình xử lý promise), và chỉ sau đó các tác vụ từ hàng đợi thông điệp (setTimeout) được thực hiện.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION