JavaScript作为单线程语言,异步操作是日常开发中无法避开的部分,早期的回调函数容易导致回调地狱,后来的Promise虽然解决了嵌套问题,但链式调用的写法依然不够直观。async/await语法的出现,让开发者可以用写同步代码的方式处理异步逻辑,极大提升了代码的可读性。

async/await的基本定义
async是修饰函数的关键字,被async修饰的函数会返回一个Promise对象。如果在async函数内部返回普通值,这个值会被自动包装成resolved状态的Promise。await关键字只能用在async函数内部,它的作用是暂停当前async函数的执行,等待右侧的Promise完成,然后返回Promise的结果,再继续执行后续代码。
基础使用示例
下面是一个简单的async/await使用示例,模拟异步获取用户数据的场景:
// 模拟异步请求用户数据的函数,返回Promise
function getUserData(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: userId, name: '张三', age: 25 });
}, 1000);
});
}
// 使用async/await调用异步函数
async function fetchUser() {
console.log('开始获取用户数据');
// 等待getUserData执行完成,拿到返回结果
const user = await getUserData(1);
console.log('获取到的用户数据:', user);
console.log('用户数据获取完成');
}
// 执行函数
fetchUser();
上述代码中,await会暂停fetchUser函数的执行,直到getUserData返回的Promise完成,才会把结果赋值给user变量,然后继续执行后面的打印语句,整个流程和同步代码的执行顺序完全一致。
async/await的执行原理
async/await本质上是对Promise的语法糖,并没有引入新的异步执行逻辑,它的底层依然是基于Promise的事件循环机制运行的。当async函数执行到await时,JavaScript引擎会暂停当前函数的执行,把后续的代码放到微任务队列中,等待await后面的Promise状态变为fulfilled之后,再把微任务取出继续执行。
需要注意的是,await只能暂停当前async函数的执行,不会影响外部其他代码的运行,下面的示例可以说明这一点:
function asyncTask() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('任务完成');
}, 1500);
});
}
async function run() {
console.log('async函数开始执行');
const result = await asyncTask();
console.log('await之后的结果:', result);
}
console.log('外部代码开始');
run();
console.log('外部代码结束');
执行上述代码后,输出顺序为:外部代码开始、async函数开始执行、外部代码结束、await之后的结果:任务完成。可以看到,await暂停的只是run函数内部的代码,外部的打印语句依然正常执行,符合JavaScript事件循环的规则。
async/await的错误处理
使用await时,如果后面的Promise变为rejected状态,会直接抛出错误,需要使用try...catch来捕获,避免错误导致程序异常终止。如果不处理错误,这个错误会向上冒泡,直到被最外层的错误捕获机制处理。
下面是错误处理的示例:
// 模拟可能失败的异步请求
function requestData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟请求失败
reject(new Error('请求数据失败'));
}, 1000);
});
}
async function handleRequest() {
try {
const data = await requestData();
console.log('请求到的数据:', data);
} catch (error) {
console.log('捕获到错误:', error.message);
} finally {
console.log('请求流程结束');
}
}
handleRequest();
如果不需要针对每个await都写try...catch,也可以在调用async函数的时候用catch捕获错误,因为async函数本身返回的是Promise:
async function test() {
const result = await Promise.reject('出错了');
return result;
}
test().catch((err) => {
console.log('捕获到错误:', err);
});
async/await的常见使用场景
串行执行多个异步任务
如果需要多个异步任务按顺序执行,后面的任务依赖前面的任务结果,用async/await写会非常清晰:
// 模拟获取用户ID的异步函数
function getUserId() {
return new Promise((resolve) => {
setTimeout(() => resolve(1001), 500);
});
}
// 模拟根据用户ID获取用户详情的异步函数
function getUserDetail(id) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, score: 90 }), 500);
});
}
async function getFullUserInfo() {
const userId = await getUserId();
console.log('获取到用户ID:', userId);
const userInfo = await getUserDetail(userId);
console.log('获取到用户完整信息:', userInfo);
return userInfo;
}
getFullUserInfo();
并行执行无依赖的异步任务
如果多个异步任务之间没有依赖关系,不需要串行等待,可以用Promise.all配合await提升执行效率:
// 模拟获取商品列表的异步函数
function getGoodsList() {
return new Promise((resolve) => {
setTimeout(() => resolve(['商品1', '商品2']), 1000);
});
}
// 模拟获取购物车信息的异步函数
function getCartInfo() {
return new Promise((resolve) => {
setTimeout(() => resolve({ count: 3 }), 1000);
});
}
async function initPage() {
console.log('开始并行请求数据');
// 同时执行两个异步任务,等待所有任务完成
const [goodsList, cartInfo] = await Promise.all([getGoodsList(), getCartInfo()]);
console.log('商品列表:', goodsList);
console.log('购物车信息:', cartInfo);
}
initPage();
使用async/await的注意事项
- await不能用在普通函数内部,只能在async修饰的函数中使用,否则会抛出语法错误。
- 不要在循环中使用await执行无依赖的异步任务,会导致本可以并行的任务串行执行,浪费时间。如果有并行需求,提前把Promise收集起来,再用Promise.all处理。
- await后面如果不是Promise对象,会自动被转换成resolved状态的Promise,所以可以直接await一个普通值,不过这种场景没有实际意义。
- 顶层await目前已经在部分运行环境支持,可以在模块顶层直接使用await,不需要包裹在async函数中,但使用时需要确认运行环境的兼容性。
JavaScriptasync/await异步编程Promise修改时间:2026-06-16 08:54:37