async / await 是 ES 2017 新增的异步编程语法,本质是 Promise 的语法糖。 它用同步代码的写法处理异步操作,彻底消除了 Promise 链式调用的 .then() 嵌套,让异步代码的可读性和维护性达到最优。
async 用于声明一个函数为异步函数,是使用 await 的前提条件。
异步函数的返回值会自动包装成 Promise 对象
函数内部 return 普通值 → 自动包装为 fulfilled 状态的 Promise
函数内部抛出错误 → 自动包装为 rejected 状态的 Promise
可以像调用普通 Promise 一样,使用 .then() / .catch() 处理结果
// 声明异步函数
async function myAsyncFunction() {
// 直接返回普通值,自动包装为 Promise
return "Hello, World!";
}
// 调用方式与 Promise 完全一致
myAsyncFunction().then((result) => {
console.log(result); // 输出: Hello, World!
});await 用于等待一个 Promise 对象执行完成,是 async/await 的核心。
必须在 async 函数内部使用,在普通函数中使用会直接报错
暂停当前函数的执行,等待 Promise 状态变更后再继续
Promise 成功 → 返回 resolve 的结果;Promise 失败 → 抛出错误
不仅可以等待 Promise,也可等待普通值(直接返回原值)
async function fetchData() {
// 定义异步操作
const promise = new Promise((resolve) => {
setTimeout(() => resolve("Data fetched"), 2000);
});
// 等待 Promise 执行完成,直接获取结果
const result = await promise;
console.log(result); // 输出: Data fetched
}
// 调用异步函数
fetchData();实际开发中,async 与 await 固定搭配使用,完美替代 Promise 链式调用,处理顺序执行的异步任务。
示例:按顺序读取文件
结合前文的 then-fs,用同步写法实现文件顺序读取:
import thenFs from "then-fs";
async function getAllFiles() {
// 依次读取 3 个文件,上一个完成后再执行下一个
const f1 = await thenFs.readFile('./files/1.txt', 'utf8');
console.log(f1);
const f2 = await thenFs.readFile('./files/2.txt', 'utf8');
console.log(f2);
const f3 = await thenFs.readFile('./files/3.txt', 'utf8');
console.log(f3);
}
getAllFiles();await 等待的 Promise 失败时会抛出异常,必须捕获处理,否则程序会崩溃。 推荐使用 try...catch 语句捕获异常,替代 Promise 的 .catch() 方法。
import thenFs from "then-fs";
async function getAllFiles() {
try {
// 尝试执行异步操作
const f1 = await thenFs.readFile('./files/1.txt', 'utf8');
console.log(f1);
} catch (error) {
// 捕获异步操作的所有错误
console.error("文件读取失败:", error);
}
}
getAllFiles();async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
// 手动抛出 HTTP 错误
if (!response.ok) throw new Error(`HTTP error! status: ${ response.status }`);
const data = await response.json();
console.log(data);
} catch (error) {
console.error("请求失败:", error);
}
}
fetchData();await 默认会串行执行异步任务(等待上一个完成再执行下一个),存在性能损耗。 结合 Promise.all() 实现并行执行,大幅提升效率。
示例:并发读取文件
import thenFs from "then-fs";
async function getAllFilesConcurrently() {
try {
// 同时发起 3 个读文件操作,并行执行
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8')
];
// 等待所有异步操作完成,统一接收结果
const [f1, f2, f3] = await Promise.all(promiseArr);
console.log(f1, f2, f3);
} catch (error) {
console.error("读取失败:", error);
}
}
getAllFilesConcurrently();结合其他静态方法
await 可以配合所有 Promise 静态方法使用:
// 赛跑机制:谁先完成返回谁
const result = await Promise.race(promiseArr);
// 兜底机制:等待所有任务完成,无论成功失败
const result = await Promise.allSettled(promiseArr);
// 成功优先:只要一个成功就返回
const result = await Promise.any(promiseArr);同步写法:代码扁平化,无嵌套,阅读难度极低
Promise 兼容:底层基于 Promise,不改变异步本质
调试友好:断点调试时,和同步代码一样逐行执行
语法简洁:替代 .then() 链式调用,代码量大幅减少
不要对无依赖关系的异步任务使用串行 await,会严重降低性能,优先使用 Promise.all() 并发执行。
所有 await 操作必须放在 try...catch 中,防止未捕获的异常导致程序崩溃。
在 ES 模块(ESM)中,无需 async 函数,可以直接在顶层使用 await:
// 顶层 await(仅支持 ES 模块)
const data = await thenFs.readFile('./files/1.txt', 'utf8');
console.log(data);await 只能在 async 函数 / 模块顶层使用,在普通函数、回调函数中直接使用会报错。
总结:日常开发优先使用 async / await,它是目前 JavaScript 异步编程的最优方案。
async / await 是 Promise 的语法糖,用同步写法实现异步逻辑
async 修饰函数,自动返回 Promise;await 等待 Promise 完成
用 try...catch 捕获错误,用 Promise.all 实现并发优化
是现代 JavaScript 开发中处理异步操作的标准方案