async / await:更好的非同步解決方案

發表於2017-07-27

在實際開發中總會遇到許多非同步的問題,最常見的場景介面請求之後一定要等一段時間才能得到結果,如果遇到多個介面前後依賴,那麼問題就變得複雜。大家都一直在嘗試使用更好的方案來解決這些問題。最開始只能利用回撥函式,後來開始有人使用Promise的思維來搞定。到ES6中開始支援原生的Promise,引入Generator函式。

直到ES7,有了async/await。

這是一個用同步的思維來解決非同步問題的方案。

我想很多人可能還不太分得清同步與非同步的區別。如果你已經徹底瞭解了事件迴圈,那麼想必對非同步的概念應該非常瞭解。當我們發出了請求,並不會等待響應結果,而是會繼續執行後面的程式碼,響應結果的處理在之後的事件迴圈中解決。那麼同步的意思,就是等結果出來之後,程式碼才會繼續往下執行。

我們可以用一個兩人問答的場景來比喻非同步與同步。A向B問了一個問題之後,不等待B的回答,接著問下一個問題,這是非同步。A向B問了一個問題之後,然後就笑呵呵的等著B回答,B回答了之後他才會接著問下一個問題。

那麼我們先記住這個特點,async/await使用同步的思維,來解決非同步的問題。在繼續講解它的語法與使用之前,我們先介紹一下如何在我們的開發環境中支援該語法。

如果你已經知道如何配置,可跳過

一、如何在自己的開發環境中支援async/await語法

這裡主要介紹兩種方式。

1. webpack中支援該語法

首先在當前專案中使用npm下載babel-loader

然後在配置檔案webpack.confing.dev.js中配置,在module.exports.module.rules中新增如下配置元素即可。

如果你使用最新版本的create-react-app或者vue-cli來構建你的程式碼,那麼它們應該已經支援了該配置。

2. gulp中支援該語法

首先安裝gulp外掛

然後編寫任務

二、如何使用

async函式是Generator的一個語法糖。如果你不知道Generator是什麼函式也沒有關係,我們只需要知道async函式實際上返回的是一個Promise物件即可。

在宣告函式時,前面加上關鍵字async,這就是async的用法。當我們用console.log列印出上面宣告的函式fn,我們可以看到如下結果:

很顯然,fn的執行結果其實就是一個Promise物件。因此我們也可以使用then來處理後續邏輯。

await的含義為等待。意思就是程式碼需要等待await後面的函式執行完並且有了返回結果之後,才繼續執行下面的程式碼。這正是同步的效果。

但是我們需要注意的是,await關鍵字只能在async函式中使用。並且await後面的函式執行後必須返回一個Promise物件才能實現同步的效果。

當我們使用一個變數去接收await的返回值時,該返回值為Promise中resolve出來的值。

執行這個例子我們可以看出,當在async函式中,執行遇到await時,就會等待await後面的函式執行完畢,而不會直接執行next code

如果我們直接使用then方法的話,想要達到同樣的結果,就不得不把後續的邏輯寫在then方法中。

很顯然如果使用async/await的話,程式碼結構會更加簡潔,邏輯也更加清晰。

異常處理

在Promise中,我們知道是通過catch的方式來捕獲異常。而當我們使用async時,則通過try/catch來捕獲異常。

如果有多個await函式,那麼只會返回第一個捕獲到的異常。

實踐

在實踐中我們遇到非同步場景最多的就是介面請求,那麼這裡就以jquery中的$.get為例簡單展示一下如何配合async/await來解決這個場景。

為了保證邏輯的完整性,在實踐中try/catch必不可少。總之,不處理錯誤邏輯的程式設計師不是好程式設計師。

與Promise相比,個人認為async/await有一定的簡潔性,但也並非就比Promise有絕對的優勢,因此只能算是提供了另外一種稍好的方式,至於大家學習之後選擇哪種方式來解決自己的問題,這僅僅只是你的個人喜好問題。

相關文章