Promise和Async/Await


Posted by Andy Tsai on 2020-03-29

Promise是什麼?

Promise是一個ES6新語法,
MDN的解釋是 Promise 物件代表一個即將完成、或失敗的非同步操作,以及它所產生的值

用白話一點解釋是:它承諾幫你做某事,做完會通知你結果(成功or失敗)

使用方法

用new Promise建立一個 Promise 物件,
它帶有兩個參數resolve, reject,分對應成功與失敗,

function myPromise(){
    return new Promise((resolve, reject)=>{
    })
}

成功後可以用.then()抓取結果,失敗則用.catch()

function myPromise(){
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            if(true){
                resolve('Success');
            }else{
                reject('Fail');
            }
        }, 0)
    })
}


myPromise()
    .then(res => {
        console.log(res)
    })
    .catch(res => {
        console.log(res)
    })

結果:Success

Promise Chain

如果我們有多個非同步行為,無法得知每個完成的時間,
但又要讓它們依照順序執行,此時就可以用多個then來串接。

function testA() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success A')
            resolve('Success A')
             //這裡用Math.random()模擬獲取伺服器api的不定時間
        }, Math.random() * 1000)
    })
}

function testB() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success B')
            resolve('Success B')
        }, Math.random() * 1000)
    })
}

function testC() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success C')
            resolve('Success C')
        }, Math.random() * 1000)
    })
}

testA()
    .then(testB)
    .then(testC)

Promise.all和Promise.race

假設我今天是要三個非同步行為都成功後,才做下一件事,
這個時候就可以用Promise.all,它接收一組由Promise物件組成的陣列,當全都回傳resolve,它才會做下一件事,反之只要有一個reject,就會失敗。

Promise.race則是只要一個成功就會做下一件事。

function testA() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success A')
            resolve('Success A')
        }, Math.random() * 1000)
    })
}

function testB() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success B')
            resolve('Success B')
        }, Math.random() * 1000)
    })
}

function testC() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success C')
            resolve('Success C')
        }, Math.random() * 1000)
    })
}

Promise.all([
  testA(),
  testB(),
  testC()
])
.then(res => {
  console.log(res[0],res[1],res[2])
})
.catch(res => {
   console.log('失敗')
})

Async/Await

雖然說一般的Promise寫法就已經很好了,但如果要處理多個非同步事件,用好幾個.then串連還是有點不直觀,所以在JavaScript ES7版本 就出現了Async/Await,它的底層也是Promise,所以其實就是Promise的語法糖,只是寫法更直觀 更易讀易懂。

語法糖:對功能沒有影響,但讓撰寫方式更簡單的語法

用法是將Async,放在function前,宣告這個函式是一個Async函式,並且它會回傳一個Promise

Await,一定要寫在Async函式內,並搭配另一個Promise使用,它的作用是讓我們的程式依序執行,它會等待所搭配的Promise執行完成後,才會繼續往下

function testA() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success A')
            resolve('Success A')
        }, Math.random() * 1000)
    })
}

function testB() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success B')
            resolve('Success B')
        }, Math.random() * 1000)
    })
}

function testC() {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function() {
            console.log('Success C')
            resolve('Success C')
        }, Math.random() * 1000)
    })
}

async function myAsync() {
  await testA();
  await testB();
  await testC();
}
myAsync();

當遇到await,async function就會知道要先暫停,等await搭配的Promise執行完後,再繼續往下執行

結合Promise.all使用

async function fetch1() {
    return 'fetch1'
}
async function fetch2() {
    return 'fetch1'
}

async function getApi() {
    const all = await Promise.all([fetch1(),fetch2()])
}

記得嗎,async會回傳一個Promise,這裡的fetch1和fetch2函式就是利用這點創造Promise。再搭配Promise.all來完成想要的邏輯

Reference:
JavaScript概念三明治


#ES6 #Promise #javascript #Async #Await #w3HexSchool







Related Posts

Babel 入門:用 Babel 轉換太潮的 JavaScript

Babel 入門:用 Babel 轉換太潮的 JavaScript

MTR04_1127

MTR04_1127

使用Pagy製作Blog分頁(Ruby on Rails)

使用Pagy製作Blog分頁(Ruby on Rails)


Comments