【ES6】day36-promise

作者:mario 发布时间: 2026-08-27 阅读量:9 评论数:0

第三十六天:Promise — 告别回调地狱

蜗牛往上爬 · 前端工业可视化学习笔记 第 36 篇
异步是 JS 的灵魂,也是大屏的命脉——所有数据都来自接口请求。今天从回调地狱的痛点出发,理解 Promise 的三种状态、then/catch/finally 的用法,用链式调用把"金字塔嵌套"拍扁。


目录


一、为什么需要异步

JS 是单线程语言——同一时间只能做一件事。耗时操作(网络请求、定时器)如果同步等待,页面就卡死了。

console.log("1:开始请求");
setTimeout(() => console.log("2:定时器回调"), 1000);
console.log("3:同步代码");

// 输出:1 → 3 → 2(先跑完同步,再执行回调)

机制:耗时操作交给浏览器其他线程,完成后把回调放入"任务队列",JS 主线程空闲时再执行。


二、回调地狱

多个有依赖的异步操作(先登录拿 token → 再请求列表 → 再请求详情),ES5 只能层层嵌套:

login(user, (err, token) => {
  if (err) return handleError(err);
  getDevices(token, (err, devices) => {
    if (err) return handleError(err);
    getDetail(devices[0].id, (err, detail) => {
      if (err) return handleError(err);
      render(detail);  // ⚠ 四层嵌套,向右无限膨胀
    });
  });
});

痛点:嵌套深、可读性差、错误处理重复、难以复用。


三、Promise:异步的容器

Promise 保存着"未来才会有"的值,三种状态:

pending(等待)
  ├── resolve(value) → fulfilled(成功)
  └── reject(error)  → rejected(失败)

状态一旦改变,不可逆。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve({ id: "CNC-001", temp: 65 });  // 成功
    } else {
      reject(new Error("网络错误"));          // 失败
    }
  }, 1000);
});

promise
  .then(data => console.log("成功:", data))
  .catch(err => console.log("失败:", err.message));

封装模拟接口(练习用):

// 模拟请求设备数据(60% 成功率)
function fetchDevices(delay = 1000) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.4
        ? resolve([{ id: "CNC-001", temp: 65 }])
        : reject(new Error("网络超时"));
    }, delay);
  });
}

四、then / catch / finally

fetchDevices()
  .then(devices => {
    console.log("渲染列表", devices);
    return devices.length;  // ⭐ 返回值传给下一个 then
  })
  .then(count => console.log(`共 ${count} 台`))
  .catch(err => {
    // 捕获链条中任何一环的错误
    console.error("错误:", err.message);
  })
  .finally(() => {
    // 无论成败都执行(关 loading)
    console.log("请求结束");
  });

方法

执行时机

用途

then

fulfilled

处理数据、继续链

catch

rejected

统一错误处理

finally

成败都执行

收尾(关 loading)


五、链式调用拍扁嵌套

// 封装成 Promise 的三个接口
const login = user =>
  new Promise(resolve => setTimeout(() => resolve({ token: "abc" }), 500));
const getDevices = token =>
  new Promise(resolve => setTimeout(() => resolve([{ id: "CNC-001" }]), 500));
const getDetail = id =>
  new Promise(resolve => setTimeout(() => resolve({ id, temp: 65 }), 500));

// 链式调用(扁平!)
login("admin")
  .then(({ token }) => getDevices(token))
  .then(devices => getDetail(devices[0].id))
  .then(detail => console.log("详情:", detail))
  .catch(err => console.error(err.message))  // ⭐ 一处捕获全部
  .finally(() => console.log("流程结束"));

对比回调版:嵌套变扁平、错误统一处理、每步可独立复用。

链式核心规则

  • then 回调返回普通值 → 直接传给下一个 then

  • then 回调返回 Promise → 下一个 then 会等它完成

  • 中途 throw → 跳过后面的 then,直达 catch

  • catch 之后可以继续 then(链条恢复)


六、宏任务与微任务

console.log("1:同步");
setTimeout(() => console.log("2:宏任务"), 0);
Promise.resolve().then(() => console.log("3:微任务"));
console.log("4:同步");

// 输出:1 → 4 → 3 → 2
// ⭐ 微任务(Promise.then)比宏任务(setTimeout)先执行

事件循环规则:同步代码 → 清空全部微任务 → 取一个宏任务 → 再清微任务 → ……


七、总结

概念

要点

单线程

同一时间一件事,耗时操作异步处理

回调地狱

层层嵌套,难读难维护

Promise 三态

pending → fulfilled / rejected,不可逆

then

接收成功值,返回值可继续链

catch

统一捕获链条错误

finally

成败都执行,收尾用

微任务

Promise.then 优先于 setTimeout

🎯 Promise 解决了"嵌套",明天学并发控制(Promise.all 四剑客)和 async/await——异步的终极形态。

评论