什么是异步?
Async / Await是人们期待已久的JavaScript功能,它使使用异步功能更加有趣和易于理解。它基于Promises构建,并且与所有现有的基于Promise的API兼容。
名称来自async
和await
-这两个关键字将帮助我们清理异步代码:
异步-声明一个异步函数(async function someName(){...}
)。
- 自动将常规功能转换为Promise。
- 当调用异步函数时,将使用其体内返回的值进行解析。
-
等待-暂停执行异步功能。(
var result = await someAsyncCall();
)。 当放在Promise调用的前面时,
await
强制其余代码等待,直到Promise完成并返回结果。- Await仅适用于Promises,不适用于回调。
- 等待只能在
async
函数内部使用。
假设我们要从服务器中获取一些JSON文件。我们将编写一个使用axios库并将HTTP GET请求发送到的函数。https://mrwenfeng.com/page/misc.json。我们必须等待服务器响应,因此此HTTP请求自然是异步的。
在下面我们可以看到相同的函数实现了两次。首先使用Promises,然后使用Async / Await。
function getJSON(){
return new Promise( function(resolve) {
axios.get('https://mrwenfeng.com/page/misc.json')
.then( function(json) {
//从该请求的数据是可用的.then块
//我们使用resolve
resolve(json);
});
});
}
// async关键字将自动创建一个新的Promise并返回它
async function getJSONAsync(){
let json = await axios.get('https://mrwenfeng.com/page/misc.json');
// GET请求的结果在json变量中可用。
//我们就像在常规同步函数中一样
return json;
}
很明显,代码的Async / Await版本更短并且更易于阅读。除了使用的语法外,这两个函数完全相同-它们都返回Promises并使用axios的JSON响应进行解析。我们可以这样调用异步函数:
getJSONAsync().then( function(result) {
//用result做某事
});
Async / Await是否会使Promises 过时?
不会,使用异步/等待时,我们仍然在后台使用Promises。从长远来看,对Promise的良好理解实际上会对您有所帮助,强烈建议您这样做。
甚至在某些情况下,Async / Await都不削减它,我们必须回到Promises寻求帮助。一种这样的情况是,当我们需要进行多个独立的异步调用并等待所有这些异步调用完成时。
如果尝试使用async和await执行此操作,则会发生以下情况:
async function getABC() {
let A = await getValueA(); //getvaluea需要2秒才能完成
let B = await getValueB(); // getvaluea需要4秒才能完成
let C = await getValueC(); // getvaluea需要3秒才能完成
return A*B*C;
}
每个等待调用将等待上一个返回结果。由于我们一次只调用一个,因此整个功能从开始到结束将需要9秒钟(2 + 4 + 3)。
这不是一个最佳的解决方案,因为这三个变量A
,B
以及C
不依赖于彼此。换句话说,我们不需要A
在得到之前知道它的价值B
。我们可以同时获得它们,从而省去了几秒钟的等待。
要同时发送所有请求,Promise.all()
需要a。这将确保我们在继续操作之前仍然具有所有结果,但是异步调用将并行触发,而不是一个接一个地触发。
async function getABC() {
// Promise.all() 允许我们同时发送所有请求
let results = await Promise.all([ getValueA, getValueB, getValueC ]);
return results.reduce((total,value) => total * value);
}
这样,该功能将花费更少的时间。到结束时,getValueA
和getValueC
调用将已经getValueB
结束。代替总的时间,我们将有效地将执行减少到最慢请求的时间(getValueB-4秒)。
处理异步/等待中的错误
Async / Await的另一个优点是,它允许我们在一个很好的旧try / catch块中捕获任何意外错误信息。我们只需要await
像这样调用我们的函数
async function doSomethingAsync(){
try {
// 此异步调用可能失败
let result = await someAsyncCall();
}
catch(error) {
// 错误
}
}
catch子句将处理由等待的异步调用或我们可能在try块中编写的任何其他失败代码引起的错误。
如果情况需要,我们还可以在执行异步功能时捕获错误。由于所有异步函数都返回Promises,因此我们可以.catch()
在调用它们时简单地包括一个事件处理程序
//异步函数 没有try/catch块
async function doSomethingAsync(){
// This async call may fail.
let result = await someAsyncCall();
return result;
}
// 我们在调用函数时捕获错误。
doSomethingAsync().
.then(successHandler)
.catch(errorHandler);
选择并坚持使用哪种错误处理方法很重要。同时使用try / catch和.catch()可能会导致问题。
浏览器支持
大多数主要的浏览器都已提供Async / Await。这仅排除IE11-所有其他供应商将无需外部库即可识别您的异步/等待代码