JavaScript 异步函数详解:从回调地狱到优雅控制流

JavaScript 异步函数详解:从回调地狱到优雅控制流

1. 异步编程基础

为什么需要异步?

JavaScript 是单线程语言,异步操作(如网络请求、文件读写)可以避免阻塞主线程,提升性能和用户体验。

回调函数(Callback)

最早的异步模式,通过函数传递处理结果。
问题:嵌套过深会导致“回调地狱”(Callback Hell)。

function fetchData(callback) {
  setTimeout(() => {
    callback("Data received");
  }, 1000);
}

fetchData((data) => {
  console.log(data); // "Data received"(1秒后输出)
});

回调地狱示例

getUser(userId, (user) => {
  getOrders(user.id, (orders) => {
    getProducts(orders[0].id, (products) => {
      console.log(products); // 多层嵌套,难以维护
    });
  });
});

2. Promise:更优雅的异步方案

Promise 的状态

  • Pending:初始状态。
  • Fulfilled:操作成功完成。
  • Rejected:操作失败。

基本用法

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Success!"); // 或 reject("Error!");
  }, 1000);
});

promise
  .then((result) => console.log(result)) // "Success!"
  .catch((error) => console.error(error));

链式调用

解决回调地狱的关键!

fetch("/api/user")
  .then((response) => response.json())
  .then((user) => fetch(`/api/orders/${user.id}`))
  .then((response) => response.json())
  .catch((error) => console.error("Failed:", error));

Promise 工具方法

  • Promise.all():所有 Promise 成功时返回结果数组。
  • Promise.race():第一个完成的 Promise 决定结果。
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);

Promise.all([p1, p2]).then(([r1, r2]) => {
  console.log(r1 + r2); // 3
});

3. Async/Await:同步风格的异步代码

基本语法

async 标记异步函数,await 等待 Promise 完成。

async function fetchUser() {
  try {
    const response = await fetch("/api/user");
    const user = await response.json();
    console.log(user);
  } catch (error) {
    console.error("Failed:", error);
  }
}

错误处理

  • try/catch 捕获异常。
  • 或通过 .catch() 处理。
async function loadData() {
  const data = await fetchData().catch((error) => {
    console.error("Fallback data");
    return defaultData;
  });
  console.log(data);
}

并行优化

避免不必要的串行等待:

// 错误:串行执行(耗时 2000ms)
const a = await fetchA(); // 1000ms
const b = await fetchB(); // 再1000ms

// 正确:并行执行(耗时 1000ms)
const [a, b] = await Promise.all([fetchA(), fetchB()]);

4. 高级应用与性能优化

1. 取消异步操作

  • AbortController:取消 fetch 请求。
const controller = new AbortController();
setTimeout(() => controller.abort(), 500); // 500ms后取消

fetch("/api/data", { signal: controller.signal })
  .catch((err) => {
    if (err.name === "AbortError") {
      console.log("Request aborted");
    }
  });

2. 生成器 + Promise

function*yield 实现更灵活的异步控制流。

function* asyncGenerator() {
  const result = yield fetch("/api/data");
  console.log(result);
}

const gen = asyncGenerator();
gen.next().value.then((data) => gen.next(data));

3. 异步迭代(for-await-of)

遍历异步数据流(如分页接口):

async function processAsyncData() {
  const asyncIterable = getAsyncDataStream(); // 返回异步迭代器
  for await (const data of asyncIterable) {
    console.log(data);
  }
}

5. 实战对比:回调 vs Promise vs Async/Await

场景回调函数PromiseAsync/Await
简单异步任务✅ 简单✅ 链式调用✅ 代码直观
错误处理❌ 多层嵌套难维护.catch() 统一处理try/catch 同步风格
并行任务❌ 手动协调Promise.allawait Promise.all
可读性❌ 差✅ 较好✅ 最佳

总结

  1. 回调函数:基础但易导致嵌套地狱。
  2. Promise:通过链式调用解耦异步逻辑。
  3. Async/Await:以同步写法写异步代码,推荐首选。
  4. 高级场景:取消请求、生成器、异步迭代等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王小玗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值