第 14 周总结:异步编程 — ES6 最重要的一战收官
蜗牛往上爬 · 前端工业可视化学习笔记 第 14 周总结
本周拿下前端的核心难点:异步编程。从回调地狱到 Promise 三态,从 Promise.all 并发到 async/await 同步化写法,最后用 fetch + 模拟接口完成大屏数据加载实战(loading / 并发 / 降级 / 重试)。大屏的命脉已通。
目录
一、本周学了什么
知识图谱
异步编程
├── 基础认知
│ ├── 单线程:同一时间一件事
│ └── 耗时操作 → 任务队列 → 空闲时执行
│
├── 回调 → Promise
│ ├── 回调地狱:嵌套深、错误重复
│ ├── 三态:pending → fulfilled / rejected(不可逆)
│ ├── then(成功/继续链)、catch(统一捕获)、finally(收尾)
│ └── 链式规则:返回值传递 / 返回 Promise 等待 / throw 跳到 catch
│
├── 并发控制
│ ├── all:全部成功(大屏聚合)
│ ├── race:第一个完成(超时控制)
│ ├── allSettled:永不失败(部分成功)
│ ├── any:第一个成功(最快源)
│ └── 顺序 vs 并发:有依赖 await 串行,无依赖 all 并发
│
├── async/await
│ ├── async 函数永远返回 Promise
│ ├── await 拿 resolve 值
│ ├── try/catch 捕获错误
│ └── 写法像同步,逻辑最清晰
│
└── fetch 与实战
├── response.ok 必查(404 不 reject)
├── response.json() 也是异步
├── loading / 降级 / 重试 工程套路
└── 微任务(then)先于宏任务(setTimeout)
二、核心知识速记
三条铁律
fetch 必查
response.ok——404/500 不会自动 reject无依赖的请求用
Promise.all并发——别在 for 循环里 awaitasync/await 错误必须 try/catch——不 catch 就静默失败
高频写法
// 并发请求 + 解构
const [devices, alerts, output] = await Promise.all([
fetchDevices(), fetchAlerts(), fetchOutput()
]);
// 完整请求套路
async function load() {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error(err.message);
return null;
}
}
// 超时控制
Promise.race([
fetch(url),
new Promise((_, rej) => setTimeout(() => rej(new Error("超时")), 3000))
]);
// 非核心接口降级
const alerts = await fetchAlerts().catch(() => []);
四剑客速查
在工业可视化里的应用场景
三、本周踩过的坑
坑点 1:for 循环里 await,白白慢了 3 倍
// ❌ 顺序执行:3 个请求 3 秒
for (const id of ids) {
const d = await fetch(`/api/device/${id}`);
results.push(d);
}
// ✅ 并发:1 秒搞定
const results = await Promise.all(
ids.map(id => fetch(`/api/device/${id}`))
);
坑点 2:fetch 忘了查 ok,404 当成功
// ❌ 接口 404 也走 then!
const res = await fetch(url);
const data = await res.json(); // 可能是错误页的 JSON
// ✅ 手动检查
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
坑点 3:忘了 response.json() 也是异步
// ❌ 拿到的是 Promise,不是数据
const data = fetch(url).then(res => res.json());
console.log(data); // Promise {...}
// ✅ 也要 await
const res = await fetch(url);
const data = await res.json();
坑点 4:async 函数的错误没 catch,静默失败
// ❌ 错误被吞掉,控制台只有 UnhandledPromiseRejection
async function load() {
const data = await fetchDevices(); // reject 了没人管
render(data);
}
load();
// ✅ 调用处 catch 或内部 try/catch
load().catch(err => showError(err.message));
坑点 5:在普通函数里用 await
// ❌ 语法错误
function load() {
const data = await fetchDevices(); // await 只能在 async 函数内
}
// ✅ 加 async
async function load() {
const data = await fetchDevices();
}
四、自测清单
[ ] JS 为什么是单线程?异步怎么解决卡顿?
[ ] 回调地狱的三个痛点?
[ ] Promise 的三种状态?可以反向改变吗?
[ ] then 的返回值怎么传递?返回 Promise 时会怎样?
[ ] catch 能捕获链条中哪里的错误?
[ ] 微任务和宏任务谁先执行?
[ ] Promise.all 的成功/失败条件?
[ ] race / allSettled / any 分别适合什么场景?
[ ] 顺序 await 和 Promise.all 的耗时差异?
[ ] async 函数的返回值是什么?
[ ] await 的错误怎么捕获?
[ ] fetch 的 response.ok 是干什么的?
[ ] 为什么 response.json() 也要 await?
[ ] 大屏加载的降级策略怎么写?
[ ] 超时控制用哪个 Promise 方法?
五、下周预告
第 15 周:Class 与模块化(ES Module)
下周把第 10 周的"原型继承"升级为现代 Class 写法,再用 ES Module 把单文件项目拆成专业工程结构——为阶段2 的框架学习铺路。
🚀 第 14 周完成!异步编程这座大山已翻过。下周 Class + 模块化,把代码组织成真正的工程!