Skip to content

C15. 网络交互 异步回调

5.1. 🌟 fetch 方法返回一个 Promise 对象

网络请求需要时间,但 JavaScript 是单线程。fetch() 通过返回 Promise 对象,让代码在等待响应时不阻塞主线程

javascript
fetch("https://api.example.com/data")
  .then(response => {
    console.log("响应到达了"); // 成功时执行
    return response.json(); // 解析 JSON 数据
  })
  .catch(error => {
    console.error("请求失败:", error); // 出错时执行
  });
console.log("fetch 发送请求后继续执行其他代码");

Promise 的三个状态

  • pending(进行中):初始状态
  • fulfilled(已成功):操作成功完成
  • rejected(已失败):操作失败

5.2. ⭐ Promise 对象防止浏览器主线程的阻塞

如果直接同步等待网络响应,页面会卡死。Promise 通过异步机制让代码“松耦合”。

javascript
// 坏例子:同步阻塞(假设 sleep 是阻塞函数)
function badRequest() {
  const response = sleep(5000); // 主线程被卡住
  console.log("5秒后执行");
}

// 好例子:异步非阻塞
function goodRequest() {
  fetch("https://api.example.com")
    .then(() => console.log("响应到达后执行"))
    .catch(() => console.error("出错了"));
  console.log("继续执行其他操作");
}

危险操作

直接使用 while(true) 或长时间计算会导致页面无响应(卡死)

5.3. 🌟 Promise 对象具有 then 和 catch 方法

then() 处理成功结果,catch() 捕获错误。二者均返回新 Promise 对象。

javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("成功数据"), 1000);
});

promise
  .then(data => {
    console.log(data); // "成功数据"
    return "下个 then 的输入";
  })
  .then(nextData => console.log(nextData)) // "下个 then 的输入"
  .catch(error => console.error(error)); // 只有 reject 时触发

5.4. ⭐ Promise 对象可以被链式调用

链式 then 可以串联多个异步操作,形成清晰的流程。

javascript
fetch("https://api1.com")
  .then(response => response.json())
  .then(data => {
    console.log("处理第一个 API 数据");
    return fetch("https://api2.com"); // 返回新 Promise
  })
  .then(secondResponse => secondResponse.text())
  .then(text => console.log("第二个 API 文本:", text))
  .catch(error => console.error("链中任一环节出错都会触发"));

链式执行规则

  • 前一个 then 返回值会成为下一个 then 的输入
  • 遇到 catch 会中断链式,需重新 then

5.5. fetch 方法的参数

fetch(url, options)options 可配置请求细节。

参数作用示例值
method请求类型(默认 GET)"POST"
headers请求头(如 Content-Type){"Content-Type": "application/json"}
body请求体(仅 POST/PATCH 等)JSON.stringify({ key: "value" })
modeCORS 模式"no-cors"
javascript
// POST 请求示例
fetch("https://api.example.com/submit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Custom-Header": "123"
  },
  body: JSON.stringify({ username: "alice" })
});

5.6. 🌟 前端 API 请求示例

5.6.1. GET 请求获取数据

javascript
fetch("https://api.example.com/users")
  .then(response => {
    if (!response.ok) throw new Error("HTTP错误:" + response.status);
    return response.json();
  })
  .then(users => renderUserList(users))
  .catch(error => showErrorMessage(error));

5.6.2. POST 提交表单

javascript
document.querySelector("#loginForm").addEventListener("submit", (event) => {
  event.preventDefault();
  const formData = new FormData(event.target);
  fetch("/api/login", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      username: formData.get("username"),
      password: formData.get("password")
    })
  })
  .then(response => response.json())
  .then(data => {
    if (data.success) {
      alert("登录成功");
    } else {
      alert("账号或密码错误");
    }
  })
  .catch(() => alert("网络错误"));
});

知识回顾

  1. 异步核心概念
    • fetch() 返回 Promise 实现非阻塞请求
    • then() 处理成功,catch() 捕获错误
  2. Promise 特性
    • 链式调用串联多个异步操作
    • 状态不可逆(一旦完成不会变回)
  3. fetch 参数关键点
    • POST 必须设置 Content-Type
    • response.json() 解析响应体
  4. 常见陷阱
    • 忽略 response.ok 检查导致静默失败
    • 混淆 then() 返回值传递
    • 错误处理未覆盖所有可能

课后练习

  1. (单选)以下哪个是 Promise 的最终状态?

    • A. pending
    • B. fulfilled
    • C. then
    • D. catch
  2. (填空)使用 fetch 发送 POST 请求时,必须设置______头部来指定 JSON 数据类型。

  3. (代码纠错)修复以下 fetch 调用,确保正确解析 JSON:

    javascript
    fetch("https://api.example.com/data")
      .then(data => console.log(data)) // 错误:未调用 .json()
  4. (操作题)实现一个天气查询功能:

    • 输入城市名,调用第三方 API(如 OpenWeatherMap)
    • 显示温度和天气状况
    • 添加错误提示(网络错误/城市不存在)

备注: (1) 通过真实 API 调用案例强化学习效果 (2) 强调错误处理的必要性,避免静默失败 (3) 使用链式调用展示复杂异步流程

Built by Vitepress | Apache 2.0 Licensed