JavaScript Promises的出現,讓咱們能夠走出回調地獄,着實驚豔。Promises 容許咱們更好的引入和處理異步任務,雖然如此,但引入好多的 then
仍是會讓代碼變的混亂。我已經開始使用 ES2017 裏的 async
和 await
關鍵字來簡化 promises 的處理。讓咱們一睹 async
和 await
的風采!web
async
是函數聲明的關鍵字await
用於 promises 處理過程當中await
必須用在 async
聲明的函數內部,雖然 Chrome 已經支持「頂級的」的 await
async
函數返回 promises 對象,不關心函數的返回值是什麼async/await
和 promises 的底層實現是同樣的async
和 await
的好處then / catch
轉換async
和 await
簡介從實例入手要更簡單,咱們先來看一個簡單的 async/await
的使用方法:json
// 使用 async 定義函數,而後 await 才能使用 async function fetchContent() { // Instead of using fetch().then, use await let content = await fetch('/'); let text = await content.text(); // async 函數內,text 是響應值 console.log(text); // Resolve this async function with the text return text; } // Use the async function var promise = fetchContent().then(...);
首先使用 async
聲明函數;聲明以後,await
能夠用在該函數內部。await
關鍵字後面跟 promise:fetch API
。異步任務(在這個例子是 fetch
)執行以後,一直在執行完成才繼續下一個任務(並無產生阻塞)。最後這個函數處理了返回值而且返回了一個 promises 對象。promise
代碼自上而下,告別回調,異步處理變的更加簡單!瀏覽器
await
當時間容許,你必定很想將你的 promise 的代碼升級到 await
,讓咱們看下該怎麼作:babel
// Before: callback city! fetch('/users.json') .then(response => response.json()) .then(json => { console.log(json); }) .catch(e => { console.log('error!'); }) // After: no more callbacks! async function getJson() { try { let response = await fetch('/users.json'); let json = await response.json(); console.log(json); } catch(e) { console.log('Error!', e); } }
從使用多個 then
到 await
十分簡單,但你的代碼的維護性變得很高。異步
async
/ await
模式聲明 async
函數有如下方式:async
let main = (async function() { let value = await fetch('/'); })();
async function main() { let value = await fetch('/'); };
let main = async function() { let value = await fetch('/'); }; // Arrow functions too! let main = async () => { let value = await fetch('/'); };
document.body.addEventListener('click', async function() { let value = await fetch('/'); });
// Object property let obj = { async method() { let value = await fetch('/'); } }; // Class methods class MyClass { async myMethod() { let value = await fetch('/'); } }
正如你看到的,增長 async
函數十分簡單,並且能很好的適用各類函數建立的流程。函數
傳統的 promises 容許使用 catch
回調處理 rejection,當你使用 await
,最好使用 try/catch
:post
try { let x = await myAsyncFunction(); } catch(e) { // Error! }
老式的 try/catch
不如 promises 的 catch
優雅,但在這裏,它很給力!fetch
Google 的Jake Archibald在Async functions document中提出了一個完美的觀點:不要用 await
使得任務變的太序列化。也就是說對於能夠同時執行的任務,先觸發任務而後再使用 await
,而不是直接使用 await
使得任務像堆棧式同樣的存儲。
// Will take 1000ms total! async function series() { await wait(500); await wait(500); return "done!"; } // Would take only 500ms total! async function parallel() { const wait1 = wait(500); const wait2 = wait(500); await wait1; await wait2; return "done!"; }
第一個代碼塊反面例子,第二個 await
須要等待第一個 await
執行完畢後才執行,第二個代碼塊是一個更好的方法,同時觸發了兩個任務,而後才使用 await
;這樣作可使得多個異步操做同時執行!
Promise.all
等價方式Primises API 中我最愛的 API 之一就是 Promise.all
:當多有任務完成後纔會觸發回調。async / await
中沒有等價的操做,可是這篇文章提供了一個很好的解決方案:
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
請記住,async / await
和 promises 在底層實現上是一致的,因此咱們能夠簡單的等待(await)全部的 promises 任務結束!
如今大多數瀏覽器均可以使用 async
和 await
,Nodejs 同樣可用,老版本的Nodejs可使用 transform-async-to-generator 這個 babel 插件來使用 async
和 await
。Promises 依然很棒,但 async
和 await
使得它可維護性更好。