JS 入门通关手册(24):Promise:从回调地狱到异步优雅写法

回调函数虽然能实现异步,但一旦遇到多个有依赖的异步任务,就会变成嵌套多层的回调地狱,代码难读、难维护、难调试。

Promise 就是为了解决这个问题而生的。它不是新的异步功能,而是异步代码的管理方案,让异步代码可以像同步代码一样链式书写。


一、Promise 是什么?

一句话:Promise 是一个表示异步操作最终完成(或失败)的对象,它让你能把回调写法改成链式调用写法,彻底告别回调地狱。

它有三种状态:

  1. pending:等待中(初始状态)
  2. fulfilled:已成功(操作完成)
  3. rejected:已失败(操作出错)

特点:

  • 状态一旦改变,就凝固不变
  • 从 pending → fulfilled 或 pending → rejected
  • 改变后不可再修改

二、Promise 基本用法

1. 创建 Promise

javascript

运行

javascript 复制代码
const p = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    // 成功
    resolve("数据拿到了");

    // 失败
    // reject("请求失败");
  }, 1000);
});

2. 使用 then 接收结果

javascript

运行

javascript 复制代码
p.then(res => {
  console.log("成功:", res);
}).catch(err => {
  console.log("失败:", err);
});

3. 封装一个异步请求(模拟接口)

javascript

运行

javascript 复制代码
function request(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url) {
        resolve({ data: "用户数据", code: 200 });
      } else {
        reject("url 不能为空");
      }
    }, 1000);
  });
}

// 使用
request("/api/user")
  .then(res => console.log(res))
  .catch(err => console.log(err));

三、Promise 链式调用(核心:解决回调地狱)

这是 Promise 最强大的地方:then 可以返回新 Promise,继续 then。

对比回调地狱:

javascript

运行

javascript 复制代码
// 以前回调地狱
getID(function (id) {
  getUser(id, function (user) {
    getOrder(user, function (order) {
      console.log(order);
    });
  });
});

Promise 链式写法:

javascript

运行

javascript 复制代码
request("/id")
  .then(id => request("/user/" + id))
  .then(user => request("/order/" + user.id))
  .then(order => console.log(order))
  .catch(err => console.log("出错:", err));

清爽、线性、可维护!


四、Promise 常用 API

1. Promise.then()

成功时执行,可返回新 Promise 继续链式。

2. Promise.catch()

捕获任何环节的错误。

3. Promise.finally()

无论成功失败,一定执行(常用于关闭加载)。

javascript

运行

javascript 复制代码
request("/api")
  .then(res => {})
  .catch(err => {})
  .finally(() => {
    console.log("结束");
  });

4. Promise.all()

多个请求并行,全部成功才成功。

javascript

运行

javascript 复制代码
const p1 = request("/api1");
const p2 = request("/api2");

Promise.all([p1, p2])
  .then(res => console.log(res[0], res[1]))
  .catch(err => console.log("有一个失败就失败"));

5. Promise.race()

谁先完成就用谁(不管成功失败)。

javascript

运行

javascript 复制代码
Promise.race([p1, p2]).then(res => console.log("最快的结果"));

6. Promise.resolve() / Promise.reject()

快速返回成功 / 失败的 Promise。

javascript

运行

javascript 复制代码
Promise.resolve(123).then(res => console.log(res));

五、Promise 手写小案例(模拟真实接口)

javascript

运行

javascript 复制代码
// 模拟获取用户ID
function getUserId() {
  return new Promise(resolve => {
    setTimeout(() => resolve(1001), 1000);
  });
}

// 模拟获取用户信息
function getUserInfo(id) {
  return new Promise(resolve => {
    setTimeout(() => resolve({ id, name: "张三" }), 1000);
  });
}

// 模拟获取订单
function getOrder(user) {
  return new Promise(resolve => {
    setTimeout(() => resolve({ orderId: 1, userId: user.id }), 1000);
  });
}

// 链式调用(完全没有嵌套)
getUserId()
  .then(id => getUserInfo(id))
  .then(user => getOrder(user))
  .then(order => console.log("最终订单:", order));

六、常见面试题

1. Promise 有哪几种状态?

pending、fulfilled、rejected。

2. Promise 解决了什么问题?

回调地狱,让异步代码可链式、可阅读、可维护。

3. then、catch、finally 的执行顺序?

  • 成功:then → finally
  • 失败:catch → finally
  • finally 一定执行

4. Promise.all 和 Promise.race 区别?

  • all:全部成功才成功
  • race:谁快返回谁

5. Promise 是异步还是同步?

Promise 本身是同步执行 的,then/catch/finally 是微任务异步。


七、总结

  1. Promise 是异步封装对象,解决回调地狱
  2. 状态:pending → fulfilled /rejected
  3. 核心写法:new Promise((resolve,reject)=>{})
  4. 链式:.then().catch().finally()
  5. 并行:Promise.all()、Promise.race()

Promise 是现代 JS 异步的基石,下一篇我们学习 async/await ------ Promise 的语法糖,让异步代码写得和同步一模一样。

相关推荐
三十而立洋6 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁6 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄6 天前
JavaScript 隐式全局变量解析
javascript
沙蒿同学6 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端
paopaokaka_luck6 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
Hilaku6 天前
为什么死磕 1px 的团队,用户体验反而更差?
前端·javascript·程序员
陈拉斯6 天前
给公司年会写了个大屏抽奖系统:动画在前端跑,凭什么说结果没被改?
javascript
志尊宝6 天前
Vue3 零基础每日笔记(055):组件里正确使用 store——storeToRefs 解构与 $patch 批量修改
笔记·vue·html·前端开发·软件开发
yzy856 天前
Vue中下载或打开文件的JavaScript方法
前端·javascript·vue
用户298698530146 天前
在 React 中用 JavaScript 将 Word 转换为文本
前端·javascript·react.js