DEV Community

SGsSY
SGsSY

Posted on

The Most Familiar Stranger - JavaScript - 非同步

分享記錄檔 YouTube

什麼是非同步

JavaScript 是一種單執行緒語言,這意味著當程式碼在執行時,只會有一個行為可以進行。由於 JavaScript 是在瀏覽器中運行的語言,它的主要用途是與網頁交互。當用戶與網頁進行交互時,瀏覽器需要執行各種行為,例如載入圖像、發送請求、處理回應等等。如果這些行為是同步的,也就是說,瀏覽器必須等待每個行為完成才能繼續執行後面的代碼,那麼瀏覽器將會凍結,用戶體驗會受到嚴重影響。

⚠️ 單執行緒是不是就代表不能非同步呢 ?

🔥 單、多執行緒以及同步、非同步是不同的概念 !

為了解決這個問題,JavaScript 提供了非同步的方式來處理這些行為。當一個行為需要等待其他行為完成才能繼續執行時,它可以將這個操作送到到一個事件佇列中,這樣瀏覽器就可以繼續執行後面的程式了。當其他行為完成後,瀏覽器將從事件佇列中取出這個行為,並且執行它。這樣可以讓瀏覽器在等待某些行為完成時繼續執行後面的程式,從而提高用戶體驗。

Event Loop

JavaScript 的事件循環( Event Loop )是實現非同步行為的一種機制。JavaScript 的事件循環採用的是單執行緒模型,這意味著當程式碼在執行時,只會有一個行為可以進行。當一個行為需要等待其他行為完成才能繼續執行時,它可以將這個行為送到到一個事件佇列中,這樣瀏覽器就可以繼續執行後面的程式了。當其他行為完成後,瀏覽器將從事件佇列中取出這個行為,並且執行它。

事件循環的運作方式如下:

  1. 當一個非同步行為需要執行時,它將被送到到一個事件佇列中。
  2. 當所有同步行為完成後,事件循環將開始處理事件佇列中的行為。這些行為將按照它們被送到的順序依次執行。
  3. 當一個事件處理完畢後,事件循環將從事件佇列中取出下一個事件,並且執行它。
  4. 事件循環將不斷地從事件佇列中取出事件,直到事件佇列中沒有其他事件為止。

範例展示網站:https://www.jsv9000.app/

事件循環的運作方式可以幫助開發人員更好地掌握 JavaScript 的非同步行為,從而更好地開發程式。在開發 JavaScript 時,明白事件循環是非常重要的,因為它可以幫助您更好地處理非同步行為,提高程式的可讀性和可維護性。

💡 會排入 Microtask queue 的事件有 Promise、async / await、MutationObserver

Promise

在 JavaScript 中,非同步的行為通常是使用回呼函式(Callback)實現的。當一個行為完成時,會呼叫回呼函式,並且將結果作為參數傳遞給回呼函式。這種方式可能會導致回呼函式的嵌套,稱為 “回呼地獄”(Callback Hell),對程式的可讀性和可維護性造成影響。

function getDataFromServer(url, callback) {
  setTimeout(function() {
    var data = "Some data from " + url;
        // callback
    callback(data);
  }, 1000);
}

getDataFromServer('https://example.com', function(data) {
    // another callback !
  processData(data, function(result) {
        // callback again !!
    renderResult(result, function(html) {
            // endless callback !!! 
      document.getElementById('result').innerHTML = html;
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

為了解決這個問題,ES6 引入了 Promise。Promise 是一個表示非同步行為的物件,當一個行為完成時,Promise 將返回一個結果或一個錯誤。Promise 提供了 then 方法,可以將回呼函式傳入 Promise 物件,當 Promise 物件完成時,then 方法將被呼叫。這樣可以避免回呼函式的嵌套,提高程式的可讀性和可維護性。

// 以下是使用 Promise 的方式重寫該程式

function getDataFromServer(url) {
    return new Promise(function(resolve, reject) {
        // call api ...
        // then resolve data
        resolve(data);
    });
}

getDataFromServer('https://example.com')
    .then(function(data) {
        return processData(data);
    })
    .then(function(result) {
        return renderResult(result);
    })
    .then(function(html) {
        document.getElementById('result').innerHTML = html;
    })
    .catch(function(error) {
        console.error(error);
    });
Enter fullscreen mode Exit fullscreen mode

Async / Await

除了 Promise 外,ES7 引入了 Async / Await。Async / Await 是基於 Promise 的一種語法糖,它能夠更簡單地實現非同步行為。Async 函式是一個返回 Promise 物件的函式,而 Await 運算符用於等待 Promise 物件的結果。Async/Await 可以讓非同步程式碼看起來像同步程式碼,提高了程式的可讀性和可維護性。

function getDataFromServer(url) {
  return new Promise(function(resolve, reject) {
    // call api ...
        // then resolve data
        resolve(data);
  });
}

async function processData() {
  var data = await getDataFromServer('https://example.com');
  var result = await processData(data);
  var html = await renderResult(result);
  document.getElementById('result').innerHTML = html;
}

processData();
Enter fullscreen mode Exit fullscreen mode

Top comments (0)