云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

JavaScript异步编程Async/Await详解

jxf315 2025-05-30 15:34:10 教程文章 4 ℃

JavaScript 异步编程 Async/Await 使用详解:从原理到最佳实践

一、Async/Await 基础

  1. 核心概念

O async 函数:声明一个异步函数,隐式返回 Promise 对象。若函数返回非 Promise 值,会被自动包装为 Promise.resolve(value)

javascript

async function fetchData() {

return 'data';

}

// 等效于:

function fetchData() {

return Promise.resolve('data');

}

O await 表达式:暂停异步函数的执行,等待 Promise 解决。若等待的值非 Promise,则转换为 Promise.resolve(value)

javascript

async function example() {

const result = await 42; // 等同于 await Promise.resolve(42)

console.log(result); // 42

}

  1. 错误处理

O 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);

}

}

O 链式 .catch():通过返回的 Promise 处理错误。

javascript

fetchWithError().catch(error => console.error('Top-level error:', error));


二、Async/Await 原理

  1. 生成器与执行器

O 生成器函数 (function*):通过 yield 暂停执行,手动调用 next() 恢复。

O 自动执行器: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);

  1. 事件循环与微任务

O await 的暂停机制:遇到 await 时,将后续代码作为微任务加入队列,主线程继续执行其他同步任务。

O 执行顺序示例

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


三、最佳实践与常见问题

  1. 并行执行优化

O 错误示例:串行等待导致性能损失。

javascript

async function slowExample() {

const a = await fetchA(); // 等待A完成

const b = await fetchB(); // 再等待B完成(总耗时 = A + B)

}

O 正确做法:使用 Promise.all 并行执行。

javascript

async function fastExample() {

const [a, b] = await Promise.all([fetchA(), fetchB()]); // 并行执行(总耗时 ≈ Max(A, B))

}

  1. 循环中的异步处理

O for 循环串行执行

javascript

async function processArray(array) {

for (const item of array) {

await processItem(item); // 逐个处理

}

}

O map + Promise.all 并行执行

javascript

async function processArrayParallel(array) {

await Promise.all(array.map(item => processItem(item))); // 并行处理所有项

}

  1. 错误处理封装

O 高阶函数统一处理:减少重复 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);

  1. 避免常见陷阱

O forEach 中的陷阱:无法正确等待异步操作。

javascript

// 错误示例:所有操作并行启动,但无法等待完成

array.forEach(async item => await processItem(item));

// 正确做法:使用 for...of 或 Promise.all

O 顶层 await:仅在 ES Modules 中可用,避免在非模块脚本中使用。


四、总结与扩展

  • 核心优势:以同步形式编写异步代码,提升可读性和可维护性。
  • 适用场景:适用于需要顺序执行、复杂错误处理的异步流程。
  • 进阶技巧:结合 Promise.race 处理超时、利用 async 函数作为 Express/Koa 中间件等。

通过理解原理、遵循最佳实践,可充分发挥 Async/Await 的优势,编写高效、健壮的异步 JavaScript 代码。

Tags:

最近发表
标签列表