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" }) |
mode | CORS 模式 | "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("网络错误"));
});
知识回顾
- 异步核心概念:
fetch()
返回Promise
实现非阻塞请求then()
处理成功,catch()
捕获错误
- Promise 特性:
- 链式调用串联多个异步操作
- 状态不可逆(一旦完成不会变回)
- fetch 参数关键点:
POST
必须设置Content-Type
response.json()
解析响应体
- 常见陷阱:
- 忽略
response.ok
检查导致静默失败 - 混淆
then()
返回值传递 - 错误处理未覆盖所有可能
- 忽略
课后练习
(单选)以下哪个是 Promise 的最终状态?
- A. pending
- B. fulfilled
- C. then
- D. catch
(填空)使用 fetch 发送 POST 请求时,必须设置______头部来指定 JSON 数据类型。
(代码纠错)修复以下 fetch 调用,确保正确解析 JSON:
javascriptfetch("https://api.example.com/data") .then(data => console.log(data)) // 错误:未调用 .json()
(操作题)实现一个天气查询功能:
- 输入城市名,调用第三方 API(如 OpenWeatherMap)
- 显示温度和天气状况
- 添加错误提示(网络错误/城市不存在)
备注: (1) 通过真实 API 调用案例强化学习效果 (2) 强调错误处理的必要性,避免静默失败 (3) 使用链式调用展示复杂异步流程