原文地址 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);
});
查看程序输出:
