JS 執行緒與同步,非同步

單執行緒

JavaScript 是一種單執行緒的程式語言,單執行緒是一種作業系統的概念。

單執行緒的程式,有一個特性就是順序執行,就是都是一步一步來,前面還沒完成,就不會往後執行。

同步範例

輸出 吃晚餐 -> 洗澡 -> 睡覺,也就是同步執行,函式一個接一個完成

function eatDinner() {
console.log("吃晚餐");
}

function bath() {
console.log("洗澡");
}

function sleep() {
console.log("睡覺");
}

function go() {
eatDinner();
bath();
sleep();
}

go();

事件佇列

我們可以使用 setTimeout 模擬非同步行為,而setTimeout 是一個瀏覽器提供的 API ,而不是 JS 引擎本身的功能

JavaScript 本身是同步的,當他需要去呼叫其他資源使用時,因無法準確知道其完成時間,所以會以非同步的方式處理。

函式呼叫順序還是跟同步是一樣的,但在 setTimeout 裡的 function 會先移到事件佇列,等待其他同步執行完成後才執行,這邊是設定三秒後回傳,就算是設定 0 秒他也會將函式移動到事件佇列

佇列內的任務會在主執行緒完成它自己的工作後執行,所以它並不會阻擋後續 Javascript 程式碼的執行。在佇列內的操作會盡快完成並將結果回傳給 Javascript 環境。

function getOffWork() {
console.log("下班");
}

function callMom() {
console.log("打電話給媽媽");
setTimeout(function () {
console.log("媽媽回電");
}, 3000);
}

function buyDinner() {
console.log("買晚餐");
}

function go() {
getOffWork();
callMom();
buyDinner();
}

go();

輸出如下

再來看看執行堆疊,程式也是依序執行,但會先將 setTimeout 你的函式先放到事件佇列等待同步執行完畢,在執行

結語

  • setTimeout 有設定秒數,可以知道哪個函式需先被執行
  • setTimeout 沒有設定秒數,則函式執行順序為隨機,此情況可以用 Promise(代表瀏覽器述說著:「我承諾我會盡快給予你一個答覆」) 來解決
  • 監聽事件則是等使用者觸發才會執行事件,稱為非同步回呼
  • AJAX ,Axios,Fetch 也是非同步事件,須等他回傳資料才會有資料