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

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay