同步 Sync 與非同步 Async


Posted by Erica on 2021-04-08

同步與非同步的差異

在學習同步與非同步的概念時很容易混淆,「同步」光看字面上的意思,可能會誤解成「所有動作同時進行」,而其實正好相反。
就以去夜市點餐來說明,如果今天想買的東西有:雞排、QQ球、珍奶。

  • 同步 (sync):先去買雞排 -> 再去買QQ球 -> 然後再買珍奶。
    像這樣「先完成 A 才能做 B、C、D ...」的運作方式我們就會把它稱作「同步」。

  • 非同步 (async):再找兩個朋友幫忙,每人去一個攤位買一樣東西,就可以同時買好雞排、QQ球、珍奶。

所以同步的概念其實比較像是「一步一步來處理」的意思。
非同步則是,我不用等待 A 做完才做 B、C,而是這三個事情可以同時發送出去。

Promise

Promise 是 ES6 新增的建構函式,用來優化非同步的語法,增加可讀性。
Promise 字面上翻譯就是「約定、承諾」,可以想像成 A 和 B 約定要做某件事情,接著回報處理結果,而這個結果只能是「完成」或「拒絕」。

function asyncFunction (value) {
    return new Promise((resolve, rejecte) => {
        value ? resolve('處理完成的結果') : reject('被拒絕的原因')
    })
}

為什麼需要 Promise?

JavaScript 是單執行緒(同步)的程式語言,一次只能處理一件事情,所以遇到非同步的事件時,就會先把程式碼放到「事件佇列」,等到所有事件處理完後才會執行非同步事件。

console.log('開始') // 執行順序 1

setTimeout(() => {
  console.log('非同步事件') // 執行順序 3
}, 0)

console.log('程式碼結束') // 執行順序 2

狀態

Promise 在處理非同步的事件的過程中,包含不同的進度狀態

  • Pending:尚未得到結果
  • Resolved:事件已經執行完畢且成功操作,回傳 resolve 的結果
  • Rejected:事件已經執行完畢但操作失敗,回傳 reject 的結果

接收回傳

Promise 可以用 thencatch 來接收並回傳結果:
then 可以同時接收成功、失敗結果,而 catch 只接收失敗結果

  • 使用 catch 接收失敗:
    在任何階段遇到 reject 時,都會直接跳到 catch,之後的 then 都不會執行
    雖然 catch 依然可以使用 return 繼續串接,但很少這樣使用
promise(1)
    .then(success => {
        console.log(success) // resolve 接收成功 // '1'
        return promise(0)    // return promise(0) -> reject 跳到 catch
    })

    .then(success => {       // 因為上面出現 reject 所以跳過
        console.log(success)
        return promise(3)
    })

    .catch( fail => {
        console.log(fail)    // reject 接收失敗 // '失敗'
    })
  • 使用 then 接收失敗:
    then 中的兩個函式必定執行其中一個,可以用此方式確保所有的鏈接都能夠被執行
promise(0)
    .then(success => {
        console.log(success)
        return promise(1)
    }, fail => {
        console.log(fail)     // reject 接收失敗 // '失敗'
        return promise(2)     // return promise(2)
    })

    .then(success => {
        console.log(success) // resolve 接收成功 // '2'
        return promise(0)    // return promise(0)
    }, fail => {
        console.log(fail)
        return promise(4)
    })

    .then(success => {
        console.log(success)
    }, fail => {
        console.log(fail)     // reject 接收失敗 // '失敗'
    })

完成

  • 最後可以使用 finally 來確認工作結束
  • finally 不帶有任何參數,適合用來確認 Ajax 已經讀取完成
promise(1)
    .then(success => {
        console.log(success)
    }).finally(() => {
        console.log('done')
    })

參考文章:


#javascript







Related Posts

JavaScript迴圈

JavaScript迴圈

金魚系列、 RWD (上)

金魚系列、 RWD (上)

進階 React Component Patterns 筆記(下)

進階 React Component Patterns 筆記(下)


Comments