本篇文章主要討論 javascript 的非同步程式設計,Promise 是什麼和 Promise 執行順序

Javascript 基礎觀念

Javascript 主要執行緒 (Main Thread)

Main thread 是瀏覽器處理事件和繪製畫面的執行緒,預設情況下,瀏覽器只使用「一個執行緒」執行所有 Javascript。
所以「長運行時間的函式」會阻塞執行緒,導致事件處理或繪製畫面的延遲,影響使用者體驗。

除非使用 Web Worker,否則瀏覽器只會在主要執行緒上運行

分析長運行時間的函式

  • CPU Bound: 運行函式的大部份時間都是計算、邏輯判斷等,需要使用大量 CPU 資源的指令
  • I/O Bound: 運行函式的大部份時間等待鍵盤、滑鼠、硬碟、網路等事件觸發,不需要使用大量 CPU 資源的指令

處理長運行時間的函式

  • CPU Bound: 使用 Web Worker 方式增加執行緒,進行平行運算
  • I/O Bound: 使用非同步的 API

Javascript 非同步程式設計

非同步程式設計

在 javascript 中非同步的函式 (參考資料):

  • Making HTTP requests using fetch()
  • Accessing a user’s camera or microphone using getUserMedia()
  • Asking a user to select files using showOpenFilePicker()

順帶一提,為什麼不提供同步 request,參考這篇文章 Synchronous and asynchronous requests,同步 request 會造成阻塞,尤其是在網路環境很差的時候,很多瀏覽器已經停用同步 request 功能

Promise 是什麼

Promise 是非同步函式回傳的結果,主要解決非同步程式 Callback 的問題

Promise 的生命週期

  1. pending: 當 Promise 建立,且不是成功或失敗狀態,則視為等待狀態
  2. fulfilled: 成功狀態,進入 then()
  3. rejected: 拒絕狀態,進入 catch()

Promise 讀取結果

採用 Promise Chain 方式,將 fetch 回傳的 Promise後面接 then() 讀取回傳

1
2
3
fetch(file)
.then(x => x.text())
.then(y => myDisplay(y));

Promise 執行順序

上面提到 Javascipt 是預設單一執行緒運行,那非同步執行時,運行的順序是如何。

以下以一個範例進行說明,main 函式會去要求資源,並在整個流程中插五個戳記,
分別是 show(1) ~ show(5)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function main() {
const url = "https://randomuser.me/api"
fetchMethod_1(url)
fetchMethod_2(url)
show(1)
}

function fetchMethod_1(url) {
fetch(url).then(() => show(2))
show(3)
}

function fetchMethod_2(url) {
fetch(url).then(() => show(4))
show(5)
}

function show(num) {
console.log(num)
}

範例程式的結構

main 包含三個 function,執行順序是 fetchMethod_1, fetchMethod_2 和 show(1)

program-structure
圖1 範例程式的結構

範例程式的執行順序

在運行時 fetch 會立刻回傳 Promise,並且在離開 main 的時候,等待 Promise_1 回傳,結束後再等待 Promise_2 回傳

program-ordering
圖2 範例程式的執行順序

參考資料