javascript异步
让我们看一下ES2017中引入的一些新语法,以帮助组织有关promise的代码。 在许多情况下,这种新语法(即async
和await
关键字)将帮助您编写更具可读性和可维护性的异步代码,但这并非没有缺点。 我们将首先研究如何使用async
和await
,然后讨论使用async
和下游的一些含义。
首先,我们将使用Promise布局一个简单的示例,然后将其重构为使用async
/ await
。 在我们的示例中,我们将使用基于承诺的HTTP库axios 。
let getUserProfile = (userId) => {
return axios.get(`/user/${userId}`)
.then((response) => {
return response.data;
})
.catch((error) => {
// Do something smarter with `error` here
throw new Error(`Could not fetch user profile.`);
});
};
getUserProfile(1)
.then((profile) => {
console.log('We got a profile', profile);
})
.catch((error) => {
console.error('We got an error', error)
});
上面的代码定义了一个函数,该函数需要一个用户ID并返回一个promise(返回类型为axios.get().then().catch()
)。 它调用HTTP端点以获取配置文件信息,并将通过配置文件进行解析或因错误而拒绝。 这很好用,但是getUserProfile
中有很多语法使我们的实际业务逻辑getUserProfile
:
.then((response) => {
/* important stuff */
})
.catch((error) => {
/* more important stuff */
});
JavaScript异步/等待逐步
输入async
/ await
。 这些函数使您可以在没有所有then
情况下使用promise并catch
语法,并使异步代码可读。 如果将其添加到计算为承诺的表达式之前,则await
将等待该承诺解决,此后其余功能将继续执行。 await
函数只能在async
函数内部使用, async
函数之前是async
操作符。 如果一个承诺实现了一个值,您可以像这样分配该值:
let someFunction = async () => {
let fulfilledValue = await myPromise();
};
如果承诺因错误而被拒绝,则await
运算符将引发错误。
让我们使用async
/ await
逐步重写getUserProfile
函数。
1.将async
关键字添加到我们的函数中,使其成为异步函数。 这使我们可以在函数体中使用await
运算符。
let getUserProfile = async (userId) => {
/* business logic will go here */
};
2.在我们的promise上使用await
关键字并分配解析值:
let getUserProfile = async (userId) => {
let response = await axios.get(`/user/${userId}`);
/* more to do down here */
}
3.我们要返回解析后的response
值的data
属性。 不必将其嵌套在then
块中,我们只需返回值即可。
let getUserProfile = async (userId) => {
let response = await axios.get(`/user/${userId}`);
return response.data;
/* more to do down here */
}
4.添加错误处理。 如果我们的HTTP失败并且Promise被拒绝,则await
运算符会将被拒绝的消息作为错误抛出。 我们需要抓住它并重新抛出我们自己的错误。
let getUserProfile = async (userId) => {
try {
let response = await axios.get(`/user/${userId}`);
return response.data;
} catch (error) {
// Do something smarter with `error` here
throw new Error(`Could not fetch user profile.`);
}
};
JavaScript异步/等待陷阱
我们减少了一些字符的语法使用量,但是更重要的是,我们可以逐行阅读代码,就好像它是同步代码一样。 但是,您应该注意一些粘性斑点。
添加异步会悄悄地更改函数的返回值。 当需要将异步调用添加到先前的同步函数时,转向async
/ await
引起了很多混乱。 您可能会认为您可以添加async
并await
,其他所有内容将按预期继续工作,但是async
函数会返回promise。 因此,如果将函数更改为异步函数,则需要确保已对所有现有函数调用进行调整以适当地处理Promise。 公平地说,如果使用传统的Promise语法,检查预先存在的函数调用也将是您需要做的事情,但是async
函数并不是很明显。
使用异步/等待意味着必须在某个地方处理承诺。 一旦在某个地方添加了异步函数,就可以实现承诺。 您将需要确保任何调用async函数的函数要么将结果作为promise处理,要么使用async
/ await
本身。 如果异步函数是深层嵌套的,则导致该函数调用的函数堆栈也可能是异步函数。 同样,此问题并非特定于async
/ await
,也将是promise的问题。 但是,在某个时候,您需要有一个承诺。 如果您一直在调用堆栈中冒泡async
/ await
,那么最终您将到达无法使用await
的全局上下文。 在某些地方,您将不得不以传统的承诺方式处理异步功能。
使用异步/等待还需要使用try / catch。 如果您使用async
处理可能被拒绝的任何诺言,则必须使用try
/ catch
。 这通常不是常用的语言功能。 我已经看到它几乎仅在库中使用,其中检测某些功能的唯一方法是尝试某些功能并相应地捕获错误。 当然,这是一个广义的概括,但是我的观点是,多年不用使用try
/ catch
就能编写可靠的惯用JavaScript是可能的。 采用async
/ await
要求您也采用try
/ catch
。
尽管使用async
/ await
有几个缺点,但它可以大大提高依赖promise的代码的可读性。 下周,我们将进行总结,并涵盖导致最大混乱的承诺的一些细节。 与往常一样,如有任何评论或问题,请在Twitter上与我联系。
翻译自: https://www.infoworld.com/article/3328099/javascript-async-and-await-explained.html
javascript异步