JavaScript 核心觀念(9)-執行環境與作用域-執行緒與同步、非同步

前言

這個章節開始是 JavaScript 中的重點觀念,也就是常見的 JavaScript 非同步、同步以及單執行緒的問題。

單執行緒

再講單執行緒之前,我們先來了解一下什麼是執行緒。

執行緒這個名詞最常見於電腦的硬體 CPU,舉例這邊我隨機截圖 PC home 的 Intel CoreI7-9700

核心/執行緒:8 / 8

在上述途中我們可以看到執行緒 8,這個執行緒 8 代表什麼呢?簡單來講執行緒就是它可以同時做幾件事情,例如你可以打開 Word 又打開 Chrome 然後再打開 PS 軟體等等…而這些行為都可以交由給各個執行緒處理,這樣子的好處在於我們不會因為打開 PS 軟體而導致 Word 軟體 Lag 又或者是打開 Chrome 結果 PS 軟體 Lag 等問題,而核心的數量並不代表執行緒這要注意一下舉例 AMD 的 AMD Ryzen 9-3950X 就是 16 核心但卻有 32 執行緒唷~

AMD Ryzen 9-3950X

那基本上執行緒的概念就是一個模擬出來的核心,因此千萬不要認為幾核心就會對應幾執行緒。

了解基本執行緒後我們回頭講一下 JavaScript,JavaScript 其實是一個單執行緒的程式語言,因此它一次只能做一件事情,注意這是重點一次只能做一件事情

因此 JavaScript 必須先做完某一件事情,才能去做其他事情,以生活化的例子來講小明只能先吃完早餐再打給漂亮阿姨最後再去洗碗,他一次只能做一件事情。

又是漂亮阿姨

因此若小明吃早餐同時又打電話給漂亮阿姨並且又洗碗,那麼這就是多執行緒,那多執行緒的語言舉例最知名的 Java 就是多執行緒。

非同步

非同步

在這邊可能會有人說「可是 JavaScript 不是有非同步嗎?這不是多執行緒的概念嗎?他不是同時做很多事情了嗎?」,簡單來講執行緒是針對系統的本身,而非同步則是針對程式語言的本身

同步的概念,就是當程式碼執行時他一定會依序做完才往下做,例如以下程式碼

1
2
3
4
5
6
7
8
9
10
11
12
function a() {
console.log('a');
}
function b() {
console.log('b');
}
function c() {
console.log('c');
}
a();
b();
c();

以上面程式碼舉例來講,他一定會等 a() 執行完畢才執行 b(),在同步的概念中絕對不會因為 a() 還在取得資料中而跳到 b()

如果是非同步的話,那又會怎麼樣呢?這邊舉例一個非同步的範例程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function a() {
console.log('a');
}
function b() {
setTimeout(() => {
console.log('b');
}, 1000);
}
function c() {
console.log('c');
}
a();
b();
c();

在這邊你會發現結果是 a、c 最後才是 b,這是因為在非同步語言中,若該取得資料的行為需要時間才能夠回來的話,那麼就會被放入一個叫做事件佇列 (Event queue)

事件佇列 (Event queue)

因此 JavaScript 在執行上述程式碼時,會等全部程式碼都執行完畢,才去看 Event queue 中的事件執行完畢了沒有,因此若我們將範例程式碼改成以下,那麼你會發現結果也是一樣的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function a() {
console.log('a');
}
function b() {
setTimeout(() => {
console.log('b');
}, 0);
}
function c() {
console.log('c');
}
a();
b();
c();

原因是因為 JavaScript 一定會等 a()c() 執行完畢後才去看 Event queue 中的 b() 執行完畢了沒有。

參考文獻

可以給點牡蠣。
Google AD