promise To async/await

promise To async/await

告別 Promise 迎接 Async/Await

Imgur

先說 promise

在很久以前,那是個 JavaScript callback hell 的年代,為了處理這種處境,有人提出了 Promise 的寫法。而 Promise 也是近年開發 JavaScript 程式不可或缺的一門基礎,在 ES2015 也將 Promise 納為其中的一項標準。

非同步 function

關於非同步的文章網路上已經很多了,就不在此贅述。在這裡我直接先以 Promise 實作一個簡易的非同步程式:

promise

1
2
3
4
5
6
7
8
9
10
11
const fetch = require('node-fetch')

function fetchCat (userId) {
return fetch(`https://catappapi.herokuapp.com/users/${userId}`)
.then(response => respone.json())
.then(data => data.imageUrl)
}
const result = fetchCat (123)
console.log(result)
//http://images.somecdn.com/user-123.jpg

如果是 Async/Await?

換成 Async/Await 的話,就不必寫下 .then() 了!就像同步的程式一般,不必理會它是否為非同步。

1
2
3
4
5
6
7
8
9
10
11
const fetch = require('node-fetch')

async function fetchCat (userId) {
const response = await fetch(`https://catappapi.herokuapp.com/users/${userId}`)
const data = await response.json()
return data.imageUrl
}
const result = fetchCat (123)
console.log(result)
//http://images.somecdn.com/user-123.jpg

宣告在 function fetchCat 的 async 表示該 function 是個非同步的。而在 function 內 response與data 之前的 await 表示要等待這個非同步的結果回傳後才會繼續執行,也就是說這個 function 內的程式都變為同步了!

進階點

先看這句話

Inside a function marked as asucn, you are allowed to place the await keyword in front of an expression taht returns a prmise. When you do, the execution of the async function is paused until the promise is resoled.

MPJ

會發現其實Async/Await 是基於 promise 所完成的。

連續.then() 改成 Async/Await

promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const fetch = require('node-fetch')

function fetchCat (userId) {
return fetch(`https://catappapi.herokuapp.com/users/${userId}`)
.then(response => respone.json())
.then(user => {
const promises = user.cats.map(catId =>
fetch(`https://catappapi.herokuapp.com/cats/${catId}`)
.then(response => response.json())
.then(catData => catData.imageUrl)
)
return Promise.all(promises)
})
}
const result = fetchCat (123)
console.log(result)
//'http://images.somecdn.com/cat-21.jpg', 'http://images.somecdn.com/cat-33.jpg', http://images.somecdn.com/cat-45.jpg

Async/Await

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fetch = require('node-fetch')

async function fetchCat (userId) {
const resp = await fetch(`https://catappapi.herokuapp.com/users/${userId}`)
const user = resp.json()
const catImageUrls =[]
for (const catId of user.cats){
const resp = await fetch(`https://catappapi.herokuapp.com/cats/${catId}`)
const catData = await resp.json()
catImageUrls.push(catData.umageUrl)
}
return catImageUrls
}
const result = fetchCat (123)
console.log(result)
//'http://images.somecdn.com/cat-21.jpg', 'http://images.somecdn.com/cat-33.jpg', http://images.somecdn.com/cat-45.jpg

如果這樣你覺得不夠簡潔可以搭配 Promise.all做出reurn更簡潔的寫法取帶同步迴圈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fetch = require('node-fetch')

async function fetchCat (userId) {
const resp = await fetch(`https://catappapi.herokuapp.com/users/${userId}`)
const user = resp.json()


return await Promise.all(user.cats.map(async function (catId) {
const resp = await fetch(`https://catappapi.herokuapp.com/cats/${catId}`)
const catData = await resp.json()
return catData.imageUrl
}))
}
const result = fetchCat (123)
console.log(result)
//'http://images.somecdn.com/cat-21.jpg', 'http://images.somecdn.com/cat-33.jpg', http://images.somecdn.com/cat-45.jpg

總結

async/await 的貢獻在語法上為 Javascripte 進行大優化,原本執行多行 Promises 程式簡化成一行,不僅僅提高程式的可讀性,也是為 functional programming 量身訂造的設計。


- PS 缺少 `` Error handle`` 待補