async / await构造是在JavaScript中编写异步代码的一种相对较新的方法。 它基于承诺,因此不会阻塞主流。 这种设计的创新之处在于,异步代码变得类似于同步代码,并且行为类似。 这为程序员带来了巨大的机会。

在异步/等待出现之前,在异步程序机制的开发中使用了回调和Promise。 该材料的作者(我们今天将其翻译发表)建议您首先回顾如何以旧的方式编写代码,然后使用一个真实的示例研究async / await的用法。
回呼
以下是使用回调(回调函数)的示例代码:
setTimeout(() => { console.log('This runs after 1000 milliseconds.'); }, 1000);
使用嵌套的回调函数时,存在一个称为回调地狱的问题。 这是一个简化的代码示例来说明此问题:
asyncCallOne(() => { asyncCallTwo(() => { asyncCallThree(() => { asyncCallFour(() => { asyncCallFive(() => {
如果代码包含由彼此嵌套的回调组成的结构,则这样的代码可能很难理解,将很难维护。
承诺
这是使用promise(Promise对象)的示例代码:
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的
.then()
方法-在它的帮助下,成功解决了promise之后,您可以执行某个回调。 如果在
.catch()
的工作中出现问题,则将调用
.catch()
方法。
异步功能
使用
async
声明的函数(异步函数)使我们有机会编写简洁且不会因服务构造而过载的代码,这使我们可以获得与使用promise所获得的结果相同的结果。 应该注意的是,
async
本质上只是诺言的“语法糖”。
声明函数时,使用
async
关键字创建
async
函数。 看起来像这样:
const asyncFunction = async () => {
可以使用
await
关键字暂停异步功能。 它只能用于异步功能。 它允许您返回异步函数的结果,该结果将在此类函数完成任务的执行后提供。
比较异步函数的操作和返回字符串的promise:
async
,使用
async
使您可以编写看起来像同步的异步代码。 此代码更容易使用。
既然我们已经介绍了基本的知识,那么让我们继续进行示例。
货币换算器
▍初步准备
在这里,我们将从研究异步/等待应用程序的构造的角度创建一个简单但认知的方法。 它是一种货币转换器,使用从相应API获得的真实数据。 程序接受以某种货币表示的金额,该货币的代码以及我们要将其转换成的货币代码。 之后,程序首先通过下载汇率上的当前数据来显示结果。 该程序还会显示一个国家/地区列表,您可以在其中以指定金额的货币兑换货币。
特别是在这里,我们将使用来自两个异步信息源的数据:
- Currencylayer.com服务。 在此站点上,您将需要创建一个免费帐户并获取用于访问API的密钥(API访问密钥)。 从这里我们将获取必要的数据,以将金额从一种货币转换为另一种货币。
- 服务restcountries.eu 。 无需注册即可使用。 在这里,我们上传有关您可以在何处使用将指定金额转换成的货币的数据。
创建一个新目录并在其中
npm init
命令。 当程序向我们询问有关要创建的软件包名称的问题时,我们将介绍
currency-converter
。 您不能通过按
Enter
来回答程序的其他问题。 之后,通过在目录中运行
npm install axios --save
命令,将Axios软件包安装到我们的项目中。 创建一个名为
currency-converter.js
的新文件。
让我们开始通过在此文件中连接Axios来编写程序代码:
const axios = require('axios');
我们的项目将具有三个异步功能。 第一个将加载货币数据。 第二个将加载国家/地区数据。 第三者将收集这些数据,以用户友好的形式呈现并在屏幕上显示。
▍第一个功能是异步加载货币数据
让我们创建一个异步
getExchangeRate()
函数,该函数将接受两个参数:
fromCurrency
和
toCurrency
:
const getExchangeRate = async (fromCurrency, toCurrency) => {}
在此功能中,我们需要加载数据。 通过使用async / await构造,您可以将接收到的数据直接写到某个变量或常量。 在编写该功能的代码之前,请不要忘记
在网站上注册并获得API访问密钥。 要加载数据,我们需要以下构造:
const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]');
收到系统响应后,可以在
response
对象中的
response
处找到我们需要的数据。 这是对象片段,其中包含我们感兴趣的数据(在程序中显示为
response.data
):
{ "success":true, "terms":"https:\/\/currencylayer.com\/terms", "privacy":"https:\/\/currencylayer.com\/privacy", "timestamp":1547891348, "source":"USD", "quotes":{ "USDAED":3.673042, "USDAFN":75.350404, "USDALL":109.203989, ... "USDZWL":322.355011 } }
将带有汇率的对象放在
rate
常数中:
const rate = response.data.quotes;
基本货币代码可以在
response.data.source
找到。 我们以常量
baseCurrency
编写基础货币的代码:
const baseCurrency = response.data.source;
由于默认情况下,此API返回的数据是对美元(USD)的汇率,因此创建一个常量
usd
,我们将写入除以指定金额的汇率的结果除以1所得的结果:
const usd = 1 / rate[`${baseCurrency}${fromCurrency}`];
注意密钥的形成方式,并据此获得课程的价值。 在从API获取的对象中(上面已给出了其片段),键是以
USD
开头并以相应货币的代码结尾的字符串。 由于假定我们的程序接受字符串形式的货币代码,因此我们通过串联包含基本货币代码的字符串以及在
fromCurrency
参数中传递给函数的字符串来生成密钥。
现在,为了获得从
fromCurrency
到
toCurrence
的汇率,我们将常数
usd
乘以
toCurrency
。 看起来像这样:
const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`];
结果,我们将返回进入
exchangeRate
。 其完整代码如下所示:
const getExchangeRate = async (fromCurrency, toCurrency) => { try { const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]'); const rate = response.data.quotes; const baseCurrency = response.data.source; const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`]; return exchangeRate; } catch (error) { throw new Error(`Unable to get currency ${fromCurrency} and ${toCurrency}`); } };
请注意,常规的try / catch构造用于处理查询执行期间可能发生的错误。
▍第二个功能是异步加载国家/地区数据
我们的第二个函数
getCountries()
异步地加载有关您可以在其中使用货币的国家/地区的信息,在该货币中,我们会将另一种货币指定的金额转换为该货币,该函数将采用
currencyCode
参数:
const getCountries = async (currencyCode) => {}
要加载数据,我们使用以下命令:
const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
例如,如果我们在请求中使用
HRK
代码(克罗地亚库纳),则我们将收到一个JSON代码作为响应,其片段如下所示:
[ { "name":"Croatia", ... } ]
它是包含有关国家/地区信息的一组对象。 这些对象的
name
属性包含国家/地区的名称。 您可以使用
response.data
构造访问此数组。 我们应用
map()
数组方法从接收到的数据中提取国家/地区的名称,然后从
getCountries()
函数返回此数据,该函数将是国家/地区名称的数组:
return response.data.map(country => country.name);
这是完整的
getCountries()
函数代码:
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}`); } };
function第三功能-数据收集与输出
我们的第三个异步函数
convertCurrency ()
将接受参数
fromCurrency
,
toCurrency
和
toCurrency
货币代码和数量。
const convertCurrency = async (fromCurrency, toCurrency, amount) => {}
在其中,我们首先获得汇率:
const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);
然后我们加载国家列表:
const countries = await getCountries(toCurrency);
接下来,我们执行转换:
const convertedAmount = (amount * exchangeRate).toFixed(2);
在收集了所有必要的数据之后,我们返回程序用户将看到的行:
return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`;
这是完整的功能代码:
const convertCurrency = async (fromCurrency, toCurrency, amount) => { const exchangeRate = await getExchangeRate(fromCurrency, toCurrency); const countries = await getCountries(toCurrency); const convertedAmount = (amount * exchangeRate).toFixed(2); return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; };
请注意,此功能没有try / catch块,因为它仅适用于上述两个功能提供的结果。
▍启动程序
我们已经准备了三个功能,其中两个从各种服务加载数据,一个收集这些数据并准备输出。 现在,我们只需要调用此函数,即可将所需的所有信息传递给它。 尽管此处可以根据需要执行此操作,但是我们不会在此处实现允许通过命令行将货币和总和代码转移到命令行来调用程序的机制。 我们只是调用
convertCurrency()
函数,并向其传递必要的数据:
convertCurrency('EUR', 'HRK', 20) .then((message) => { console.log(message); }).catch((error) => { console.log(error.message); });
在这里,我们想找出多少克罗地亚克纳可以兑换20欧元,并一路找出这笔钱可以在哪些国家/地区使用。
我们通过在终端中输入以下命令来调用该程序:
node currency-converter.js
作为回应,我们得到以下内容。
程序的结果为了以防万一,这里是我们项目的完整代码。
const axios = require('axios'); const getExchangeRate = async (fromCurrency, toCurrency) => { try { const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]'); const rate = response.data.quotes; const baseCurrency = response.data.source; const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; const exchangeRate = usd * rate[`${baseCurrency}${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}`); } }; const convertCurrency = async (fromCurrency, toCurrency, amount) => { const exchangeRate = await getExchangeRate(fromCurrency, toCurrency); const countries = await getCountries(toCurrency); const convertedAmount = (amount * exchangeRate).toFixed(2); return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; }; convertCurrency('EUR', 'HRK', 20) .then((message) => { console.log(message); }).catch((error) => { console.log(error.message); });
总结
我们希望这个在实际条件下使用async / await构造的示例可以帮助那些以前不了解此构造的人弄清楚该构造。
亲爱的读者们! 如果您在实践中使用async / await构造,请分享您对此的印象。