世界上誤解最大的語言 JavaScript 之 JS 到底是同步與非同步語言?!

前言

許多網路文章都可以看到許多人都說 JavaScript 是一個非同步語言,但是經過一些事情觀念驗證後才發現,這個誤解可大了,所以這一篇就來講一下 JavaScript 到底是非同步語言還是同步語言。

JavaScript

JavaScript 在一開始主要是用於瀏覽器上運行的程式語言,也因為 JavaScript 不需要消耗伺服器的資源而非常受歡迎,但早期 JavaScript 只能用於瀏覽器使用,直到後來出現 Node.js,才改變了 JavaScript 這個語言。

首先我們在網路上 Google 都會發現人家說 JavaScript 是一個非同步單執行緒語言

首先先講單執行緒,單執行緒的簡單講就是一次只能執行一個動作,這個算好理解。

那非同步呢?首先同步的意思簡單來講就是「按部就班」的概念,它是一行一行的執行,而非同步則是它不是一行一行執行有可能會跳行執行,所以試著思考一下以下這個範例。

1
2
3
4
setTimeout(() => {
console.log('a');
},0);
console.log('b');

上面這個經典範例中,許多文章都是用這個範例來介紹 JavaScript 是一個非同步語言,因為優先出現的是 b 而非 a,但是事實上真的代表 JavaScript 是非同步語言嗎?並不是,Why?

JavaScript 在執行的時候並沒有忽略 setTimeout() 這一行語法,而是將 setTimeout 放置在 JavaScript 的一個特性中,也就是所謂的事件佇列 (event quete)。

而事件佇列在卡斯柏老師文章中有非常詳細的 範例說明

JavaScript 在執行的時候是依照同步的概念去執行的,當遇到需要非同步的事件,例如:setTimeout 此時 JavaScript 就會將它丟進事件佇列中,並執行下一行。

JavaScript 是一個同步語言

其實我們也可以從一些文章抽絲剝解翻到 JavaScript 是一個同步語言,例如我先前寫的 [JS奇怪的世界]No.6 執行環境:程式執行 就有提到「創造完變數後才會開始執行一行一行執行並賦與值」。

此外還有 stackoverflow 中的其中一篇文章 When is JavaScript synchronous? 底下也有許多人提到

  • JavaScript is always synchronous and single-threaded. (JavaScript 一直都是同步語言且是單執行緒。)
  • JavaScript is single threaded and has a synchronous execution model (JavaScript 是一個單執行緒並且具有同步執行特性的語言)
  • JavaScript is single-threaded, and all the time you work on a normal synchronous code-flow execution. (JavaScript 是一個單執行緒並且會依照程式碼同步執行)

那為什麼那麼多人會誤以為 JavaScript 是一個非同步語言呢?主要原因就是 JavaScript 的事件佇列這個特性導致。

最後 Medium 上也有一篇文章提到 JavaScript 是一個同步語言 → Is JavaScript Synchronous or Asynchronous? What the Hell is a Promise?

  • JavaScript is Synchronous (JavaScript 是同步語言)

在這一篇 Medium 底下有這幾張圖我覺得相當不錯,在一開始 JavaScript 是先執行過一次程式碼

JavaScript

後來再將需要做非同步的事件丟進事件佇列中

JavaScript

我們可以看到 JavaScript 一開始是會將所有程式碼執行一遍,並將需要做非同步事件的程式碼(function)丟進事件佇列中。

所以我們也可以試著還原看看圖片中的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function A() {
console.log('A');
}
function B() {
console.log('B');
}
function C() {
setTimeout(() => {
console.log('C');
E();
F();
G();
},0);
}
function D() {
console.log('D');
}
function E() {
console.log('E');
}
function F() {
console.log('F');
}
function G() {
console.log('G');
}
A();
B();
C();
D();

JavaScript

文章也有提到,若不希望發生事件佇列這種狀況,那麼就可以使用 Promise、Asnyc、Await 的來避免,這邊就不再多做範例,若對 Promise、Asnyc、Await 好奇可以參考這三篇文章

參考文獻

0%