摘要:Øasync 函数:声明一个异步函数,隐式返回Promise对象。若函数返回非Promise值,会被自动包装为Promise.resolve(value)。
JavaScript 异步编程 Async/Await 使用详解:从原理到最佳实践
一、Async/Await 基础
核心概念Ø async 函数:声明一个异步函数,隐式返回 Promise 对象。若函数返回非 Promise 值,会被自动包装为 Promise.resolve(value)。
javascript
async function fetchData {
return 'data';
}
// 等效于:
function fetchData {
return Promise.resolve('data');
}
Ø await 表达式:暂停异步函数的执行,等待 Promise 解决。若等待的值非 Promise,则转换为 Promise.resolve(value)。
javascript
async function example {
const result = await 42; // 等同于 await Promise.resolve(42)
console.log(result); // 42
}
错误处理Ø try/catch 捕获异常:await 后的 Promise 若被 reject,会抛出异常,可通过 try/catch 捕获。
javascript
async function fetchWithError {
try {
const data = await fetch('invalid-url');
} catch (error) {
console.error('Fetch failed:', error);
}
}
Ø 链式 .catch:通过返回的 Promise 处理错误。
javascript
fetchWithError.catch(error => console.error('Top-level error:', error));
二、Async/Await 原理
生成器与执行器Ø 生成器函数 (function*):通过 yield 暂停执行,手动调用 next 恢复。
Ø 自动执行器:Async/Await 本质是生成器 + 自动执行器的语法糖,类似 co 库的实现。
javascript
// 模拟 Async/Await 的生成器实现
function* generatorExample {
const data = yield fetchData;
console.log(data);
}
// 自动执行器(简化版)
function run(generator) {
const iterator = generator;
function handle(result) {
if (result.done) return;
result.value.then(res => handle(iterator.next(res)));
}
handle(iterator.next);
}
run(generatorExample);
事件循环与微任务Ø await 的暂停机制:遇到 await 时,将后续代码作为微任务加入队列,主线程继续执行其他同步任务。
Ø 执行顺序示例:
javascript
console.log('Start');
async function test {
console.log('Before await');
await Promise.resolve;
console.log('After await');
}
test;
console.log('End');
// 输出顺序:Start → Before await → End → After await
三、最佳实践与常见问题
并行执行优化Ø 错误示例:串行等待导致性能损失。
javascript
async function slowExample {
const a = await fetchA; // 等待A完成
const b = await fetchB; // 再等待B完成(总耗时 = A + B)
}
Ø 正确做法:使用 Promise.all 并行执行。
javascript
async function fastExample {
const [a, b] = await Promise.all([fetchA, fetchB]); // 并行执行(总耗时 ≈ Max(A, B))
}
循环中的异步处理Ø for 循环串行执行:
javascript
async function processArray(array) {
for (const item of array) {
await processItem(item); // 逐个处理
}
}
Ø map + Promise.all 并行执行:
javascript
async function processArrayParallel(array) {
await Promise.all(array.map(item => processItem(item))); // 并行处理所有项
}
错误处理封装Ø 高阶函数统一处理:减少重复 try/catch。
javascript
function withErrorHandling(fn) {
return async (...args) => {
try {
return await fn(...args);
} catch (error) {
console.error('Error in', fn.name, error);
throw error; // 可选择是否继续抛出
}
};
}
const safeFetch = withErrorHandling(fetchData);
避免常见陷阱Ø forEach 中的陷阱:无法正确等待异步操作。
javascript
// 错误示例:所有操作并行启动,但无法等待完成
array.forEach(async item => await processItem(item));
// 正确做法:使用 for...of 或 Promise.all
Ø 顶层 await:仅在 ES Modules 中可用,避免在非模块脚本中使用。
四、总结与扩展
核心优势:以同步形式编写异步代码,提升可读性和可维护性。适用场景:适用于需要顺序执行、复杂错误处理的异步流程。进阶技巧:结合 Promise.race 处理超时、利用 async 函数作为 Express/Koa 中间件等。通过理解原理、遵循最佳实践,可充分发挥 Async/Await 的优势,编写高效、健壮的异步 JavaScript 代码。
来源:老客数据一点号