非同步性

Frontend SELF TW
等級 43 , 課堂 0
開放

1.1 非同步的主要概念

JavaScript 的非同步性讓你能在背景中執行任務,而不會阻塞主執行緒。這對於可能需要花費大量時間的任務特別重要,例如網絡請求、文件讀取和計時器。現在我們來看看 JavaScript 非同步編程的基本概念並給出使用範例。

JavaScript 的單執行緒特性

JavaScript 是單執行緒的,這意味著它會在一個執行緒中順序執行代碼。然而,非同步操作允許在背景中執行任務,釋放主執行緒以進行其他任務。

Event Loop(事件循環)

事件循環(Event Loop)是 JavaScript 處理非同步任務的關鍵機制。事件循環管理消息隊列(Message Queue)和微任務隊列(Microtask Queue),確保非同步操作的執行。

  1. 消息隊列:包含任務,如事件處理器、網絡請求和計時器。這些任務依序執行。
  2. 微任務隊列:包含優先級較高的任務,相較於消息隊列中的任務。示例包括 promise 的完成和微任務中的回調函數(callbacks)調用。

事件循環不斷檢查兩個隊列,並當主執行緒變空閒時從中執行任務。

非同步操作

非同步操作允許在背景中執行任務。主要的非同步操作示例包括:

  • 計時器 (setTimeout, setInterval)
  • 事件處理器
  • 網絡請求(例如 XMLHttpRequest, Fetch API
  • 文件讀寫(在 Node.js 中)

讓我們來看看一些非同步操作的例子。

1.2 計時器

計時器允許你以延遲或定期的時間間隔執行任務。

setTimeout 使用示例

在這個例子中,setTimeout 設定了函數在 2 秒後執行。因此,先輸出 StartEnd,然後在 2 秒後輸出 Executed after 2 seconds

JavaScript
    
      console.log('Start');

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

      console.log('End');
    
  

setInterval 使用示例

在這個例子中,setInterval 每秒執行一次函數,遞增計數器並輸出其值。當計數器達到 5 時,使用 clearInterval 清除間隔:

JavaScript
    
      let counter = 0;

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

1.3 事件處理器

事件處理器允許你在用戶操作或其他事件發生時執行代碼。

事件處理器使用示例

在這個例子中,click 事件處理器被添加到按鈕。當用戶點擊按鈕時,會輸出訊息 Button clicked!

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>事件處理器範例</title>
        </head>
        <body>
          <button id="myButton">點我</button>

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

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

1.4 網絡請求

網絡請求允許你發送非同步 HTTP 請求到伺服器。

XMLHttpRequest 使用示例

在這個例子中,創建一個非同步 GET 請求到 API,當請求完成時,將響應輸出到控制台:

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 運作

為了更好理解 Event Loop,讓我們看看下面的例子:

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');
    
  

預期輸出如下:

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

在這個例子中,首先執行同步操作(console.log('Start')console.log('End'))。然後執行微任務(promise 處理器),之後才執行消息隊列中的任務(setTimeout)。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION