告別 Promise 迎接 Async/Await
先說 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)
如果是 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)
宣告在 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)
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)
如果這樣你覺得不夠簡潔可以搭配 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)
總結 async/await 的貢獻在語法上為 Javascripte 進行大優化,原本執行多行 Promises 程式簡化成一行,不僅僅提高程式的可讀性,也是為 functional programming 量身訂造的設計。
- PS 缺少 `` Error handle`` 待補