原文地址 Medium - How To Master Async/Await With This Real World Example
Async/Await
是一種書寫非同步程式碼的新方式。它是構建與 promises 之上的,所以也具有非阻塞特性。
最大的區別就在於非同步程式碼的樣式和行為看起來都比較像同步程式碼,這也是其強大之處。
之前我們寫非同步程式碼一般都使用的是 callbacks 和 promises。
回撥函式時代
setTimeout(() => {
console.log('This runs after 1000 milliseconds.');
},1000);
複製程式碼
回撥函式的問題所在 —— 臭名昭著的回撥地獄
在回撥函式中巢狀的回撥函式很快就會讓你的程式碼變成這樣:
這種情況就會讓你的程式碼變的很難理解和維護。promises 時代
const promiseFunction = new Promise((resolve, reject) => {
const add = (a, b) => a + b;
resolve(add(2, 2));
});
promiseFunction.then((response) => {
console.log(response);
}).catch((error) => {
console.log(error);
});
複製程式碼
promiseFunction 返回一個 Promise,代表該函式的過程。resolve 函式代表 Promise 例項執行完畢。
然後我們可以在 promise 函式上呼叫 .then()
和 .catch()
方法:.then()
作用是 promise 決議後執行你傳入的回撥函式,.catch()
的作用是程式出錯時執行你傳入的那個回撥函式。
Async
函式
Async
函式提供給我們一個簡明的語法,讓我們能夠用更少的程式碼來實現我們本來用 promise 得到的相同結果。可以說 Async
就是 promise 的語法糖了。
Async
函式的建立時通過在函式宣告語句之前加上 async 關鍵字,示例如下:
const asyncFunction = async () => {
// Code
}
複製程式碼
Async
非同步函式可通過 await
來暫停,該關鍵字只能用在 Async
函式內部。每當函式執行完畢,await 返回的是任何 async 函式會返回的東西。
下面是 promise 和 async/await 的區別:
// Async/Await
const asyncGreeting = async () => 'Greetings';
// Promises
const promiseGreeting = () => new Promise(((resolve) => {
resolve('Greetings');
}));
asyncGreeting().then(result =>
console.log(result)
);
promiseGreeting().then(result =>
console.log(result)
);
複製程式碼
async/await 看起來和同步程式碼相似,因而更容易理解。
基礎知識講完了,現在我們來講個實在例子。 (實際上下面這個專案中的 API 現在已經不能用了,好像是已經變成收費的了,免費部分大家可以自行查閱並實現功能,這個例子就看看 async/await 的使用即可)
匯率轉換器
專案簡介和配置
這裡將用一個簡單又實用的小專案來提高你對 Async/Await 的整體認知。
程式接收我們想要轉換的兩種貨幣程式碼以及錢數,然後基於一些 API 獲取的資料輸出正確的匯率。使用的 API 如下:
- Currency Layer —— currencylayer.com ,免費註冊以使用其 API Access Key,該 API 將給我們提供所需貨幣間的匯率。
- **Rest Countries ** —— restcountries.eu/,該 API 能告訴我們剛剛轉換的貨幣能在哪兒使用。
對於新手來說,建立一個新的目錄,在該目錄上開啟命令列執行 npm init
,確認跳過所有的步驟,然後使用 npm i --save axios
命令安裝 axios 。新建一個檔案命名為 currency-converter.js
。
現在開始進入 Async/Await
吧
我們專案的目標是要寫三個非同步函式,第一個函式作用是拿到貨幣資料,第二個函式作用是拿到城市資料,第三個函式作用是將前面獲取到的資料整理到一起並格式化輸出給使用者。
第一個函式 —— 非同步的獲取貨幣資訊
該非同步函式將接受兩個引數,fromCurrency 和 toCurrency。 現在我們需要獲取資料了,使用 async/await 時我們可以直接把獲取到的資料賦值給一個變數:
const getExchangeRate = async (fromCurrency, toCurrency) => {
const response = await axios.get('http://data.fixer.io/api/latest?access_key=[yourAccessKey]&format=1');
}
複製程式碼
我們可以直接把響應的資料中匯率資訊直接賦給一個變數:
const rate = response.data.rates;
複製程式碼
由於 API 提供的資料都是基於歐元來轉換的,所以這裡我們建立一個變數 euro
,用 1 除以我們想要轉換的貨幣:
const euro = 1 / rate[fromCurrency];
複製程式碼
最後,我們可以用我們想轉換的貨幣乘以 euro
來獲得兌換匯率:
const exchangeRate = euro * rate[toCurrency];
複製程式碼
整個函式程式碼如下:
第二個函式 —— 非同步的接收城市資料
建立一個接收貨幣程式碼為引數的非同步函式:
const getCountries = async (currencyCode) => {}
複製程式碼
然後通過 API 獲取資料:
const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
複製程式碼
然後遍歷資料返回country.name
:
return response.data.map(country => country.name);
複製程式碼
最終程式碼如下:
第三個函式 —— 合併輸出
新增 try...catch
處理異常
第一個函式:
const getExchangeRate = async (fromCurrency, toCurrency) => {
try {
const response = await axios.get('http://data.fixer.io/api/latest?access_key=f68b13604ac8e570a00f7d8fe7f25e1b&format=1');
const rate = response.data.rates;
const euro = 1 / rate[fromCurrency];
const exchangeRate = euro * rate[toCurrency];
return exchangeRate;
} catch (error) {
throw new Error(`Unable to get currency ${fromCurrency} and ${toCurrency}`);
}
};
複製程式碼
第二個函式同理:
const getCountries = async (currencyCode) => {
try {
const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
return response.data.map(country => country.name);
} catch (error) {
throw new Error(`Unable to get countries that use ${currencyCode}`);
}
};
複製程式碼
現在我們可以呼叫這個函式了:
convertCurrency('USD', 'HRK', 20).then((message) => {
console.log(message);
}).catch((error) => {
console.log(error.message);
});
複製程式碼
檢視程式輸出: