面试题答案
一键面试优势
- 代码更简洁直观:async/await 以同步代码的风格编写异步代码,相比于层层嵌套的回调函数(回调地狱)和冗长的 Promise 链式调用,逻辑更清晰,更易于理解和维护。例如,处理多个异步操作时,async/await 代码看起来就像普通的顺序执行代码,而不是像 Promise 链式调用那样不断地.then()。
- 错误处理更优雅:在 async 函数内部,可以使用 try...catch 块来捕获整个函数内异步操作抛出的错误,而不需要像 Promise 链式调用那样在每个.then() 后面都添加.catch() 来捕获错误。这使得错误处理代码更集中,减少重复代码。
- 条件控制更方便:在 async 函数中,可以像普通同步函数一样使用条件语句(如 if...else)来控制异步操作的流程,而在回调函数和 Promise 链式调用中,条件控制可能会变得复杂,尤其是涉及多个异步操作的条件判断时。
需要注意的地方
- 必须在 async 函数内部使用:await 关键字只能在 async 函数内部使用,如果在普通函数中使用会导致语法错误。
- 错误处理:虽然 try...catch 捕获错误更方便,但如果在 async 函数外部调用该函数,仍然需要通过.catch() 来捕获可能抛出的错误,否则错误可能会被忽略。
- 性能:async/await 本质上还是基于 Promise 的,在性能方面并没有比 Promise 链式调用有本质提升。过多的 await 可能会导致代码阻塞,尤其是在一些高并发场景下,需要合理使用以避免性能问题。
示例代码及执行流程
// 模拟异步 API
function asyncAPI1() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('API1 执行完毕');
resolve('API1 结果');
}, 1000);
});
}
function asyncAPI2() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('API2 执行完毕');
resolve('API2 结果');
}, 1000);
});
}
function asyncAPI3() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('API3 执行完毕');
resolve('API3 结果');
}, 1000);
});
}
async function main() {
try {
const result1 = await asyncAPI1();
console.log('result1:', result1);
const result2 = await asyncAPI2();
console.log('result2:', result2);
const result3 = await asyncAPI3();
console.log('result3:', result3);
} catch (error) {
console.error('发生错误:', error);
}
}
main();
执行流程:
- 调用
main
函数,函数开始执行。 - 遇到
await asyncAPI1()
,asyncAPI1
开始执行(这里通过setTimeout
模拟异步操作),main
函数暂停执行,直到asyncAPI1
的 Promise 被 resolved。 asyncAPI1
执行完毕(1 秒后),await
表达式返回asyncAPI1
的 resolved 值,赋值给result1
,并继续执行下一行代码,打印result1:
以及asyncAPI1
的结果。- 遇到
await asyncAPI2()
,asyncAPI2
开始执行,main
函数再次暂停,直到asyncAPI2
的 Promise 被 resolved。 asyncAPI2
执行完毕(1 秒后),await
表达式返回asyncAPI2
的 resolved 值,赋值给result2
,并继续执行下一行代码,打印result2:
以及asyncAPI2
的结果。- 遇到
await asyncAPI3()
,asyncAPI3
开始执行,main
函数又一次暂停,直到asyncAPI3
的 Promise 被 resolved。 asyncAPI3
执行完毕(1 秒后),await
表达式返回asyncAPI3
的 resolved 值,赋值给result3
,并继续执行下一行代码,打印result3:
以及asyncAPI3
的结果。- 如果在任何一个
await
操作中抛出错误,代码会跳转到catch
块,打印错误信息。