
在现代编程开发中,“异步”两个字几乎贯穿始终:你写的接口请求、定时器、事件监听、动画控制……背后都绕不开异步编程。
那到底啥是异步呢?说到异步,我们就需要结合同步来讲讲,这样就更加清晰明了。
今天这篇文章,我们来讲讲在前端编程中的异步。
简单点说:
举个栗子🌰
console.log("1. 开始做饭");
setTimeout(() => {
  console.log("2. 饭做好了");
}, 3000);
console.log("3. 玩手机中...");你将看到的输出内容是:
1. 开始做饭
3. 玩手机中...
2. 饭做好了(大约 3 秒后)这就体现了异步:做饭这件事需要 3 秒时间,不影响你“玩手机”的下一步操作。
早期处理异步的方式是回调函数(callback)。
function cook(callback) {
  setTimeout(() => {
    callback("🍳 饭做好了");
  }, 3000);
}
cook((msg) => {
  console.log(msg);
});上面的代码,貌似也没啥太大的问题,但是,如果是需要做三道菜呢?代码可能就是这样的了:
cook((msg1) => {
  console.log(msg1);
  cook((msg2) => {
    console.log(msg2);
    cook((msg3) => {
      console.log(msg3);
      // 继续嵌套……
    });
  });
});是的,这就是恐怖的“回调地狱”:
明眼人都能够看得出来,这样的代码太难维护,太容易出 bug,于是 ES6 就推出了 Promise 来解决这个问题。
一句话总结:
Promise 是 JavaScript 中处理异步操作的一种对象,它表示一个还没完成但将来一定会完成(或失败)的操作结果。
它有三个状态:
状态  | 意义  | 
|---|---|
pending  | 初始状态,进行中  | 
fulfilled  | 操作成功  | 
rejected  | 操作失败  | 
状态一旦变化,就不可逆。
我们来写一个最简单的 Promise:
const p = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve("成功啦!");
  } else {
    reject("失败了~");
  }
});
p.then((result) => {
  console.log("成功:", result);
}).catch((err) => {
  console.error("失败:", err);
});resolve(value) 表示异步任务成功,传出结果。reject(error) 表示异步任务失败。.then() 是成功的回调,.catch() 是失败的回调。你可以连续使用 .then() 来处理一系列异步任务:
new Promise((resolve) => {
  setTimeout(() => {
    console.log("1️⃣ 数据加载中...");
    resolve("原始数据");
  }, 1000);
})
  .then((data) => {
    console.log("2️⃣ 第一次处理:", data);
    return data + " + 步骤一完成";
  })
  .then((newData) => {
    console.log("3️⃣ 第二次处理:", newData);
  })
  .catch((err) => {
    console.error("发生错误:", err);
  });每个 .then() 的返回值会传给下一个 .then()。
实际开发中我们经常写这种:
fetch("https://api.example.com/user/123")
  .then((res) => {
    if (!res.ok) throw new Error("网络请求失败!");
    return res.json(); // 转成 JSON
  })
  .then((user) => {
    console.log("用户信息:", user);
  })
  .catch((err) => {
    console.error("请求失败:", err);
  });这里用的 fetch 就是一个返回 Promise 的 API。
async/await 是 ES7 对 Promise 的一种 语法糖,让我们用看起来是同步的写法来写异步代码,这使得代码可以更清晰、可读性更高。
来,让我们来感受一下差距👇
fetch("/api/data")
  .then((res) => res.json())
  .then((data) => console.log("数据:", data))
  .catch((err) => console.error("出错了", err));async function getData() {
  try {
    const res = await fetch("/api/data");
    const data = await res.json();
    console.log("数据:", data);
  } catch (err) {
    console.error("出错了", err);
  }
}
getData();将代码做了一个简单的调整之后,是不是感觉瞬间就清爽多了?
async function hello() {
  return "你好";
}
hello().then((res) => console.log(res)); // 输出 "你好"await fetch("/api"); // ❌ 语法错误
// 正确写法👇
async function load() {
  const res = await fetch("/api");
}async function load() {
  try {
    const res = await fetch("/api/bad-url");
    const data = await res.json();
  } catch (err) {
    console.error("捕获错误:", err);
  }
}如果同时发出多个请求,并且需要等全部成功后再处理,那么我们就需要使用:
const getUser = fetch("/api/user");
const getPosts = fetch("/api/posts");
const [userRes, postsRes] = await Promise.all([getUser, getPosts]);如果有多个异步任务同时执行,但是只需要谁先执行完毕就用谁,那么就可以使用:
const res = await Promise.race([fetch("/a"), fetch("/b")]);以上的代码,如果 /a 先执行完,那么就 res 就是 /a 的返回结果,如果是 /b 先返回完,那么就是 /b 的返回结果。总之,谁执行的快,谁先执行完成,res 就是谁的结果。
Promise 是前端异步编程的核心工具,而 async/await 则可以让你的代码更加优雅,如果你能够熟练掌握它们:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。