JS中调用 async 函数时会返回一个 Promise 对象(隐式转换)。当async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值,当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。
在async 函数中如果遇见 await 表达式,则 async 函数会暂停执行,等待表达式中的 Promise 解析完成后继续执行 async 函数并返回结果。
基于上面的定义,我们来对比一下如下的代码,我们就知道优化点如何排查了。
function resolveAfter2Seconds(x) {
return new Promise(resolve =>setTimeout(() => resolve(x), 2000))
}
async function fn1(x) {
var a = resolveAfter2Seconds(20)
var b = resolveAfter2Seconds(30)
return x + await a + await b
}
// prints 60 after 2 seconds
fn1(10).then(v => console.log(v))
async function fn2(x) {
var a = await resolveAfter2Seconds(20)
var b = await resolveAfter2Seconds(30)
return x + a + b
}
// prints 60 after 4 seconds
fn2(10).then(v => console.log(v))
上面的代码演示代码中,我们可以发现,不同的 await 位置声明,会直接影响到函数执行的时间。
同时,我们在处理 async 函数的返回时,针对其 reject 的场景时,try-catch 模块来进行捕获,但由于try-catch会创建独立的作用域(这算是很老的一个点了,不知新版的V8有没有进行过优化),所以会在性能上有一些损失,但是相对于代码的可读性,这一点损失也无所谓啦。
async function fn(url) {
let v
try {
v = await doSomething(url)
} catch (e) {
v = await handlerError(url)
}
return success(v)
}
// 比价丑陋的写法,通过牺牲代码的可读性来避免作用域的开辟
async function fn(url) {
let v
v = await doSomething(url).catch(err => {
v = await handlerError(url)
})
return success(v);
}