前端 Promise 全解:从原理到面试

重点总结定义:Promise 是异步编程的一种解决方案,解决了回调地狱问题,提供了统一的 API。状态:它有 Pending、Fulfilled、Rejected 三种状态,且状态不可逆。使用:构造函数是同步执行的。.then 返回新 Promise,支持链式调用。.catch 处理错误(冒泡机制)。常用 API:all(并发,全对才对)。race(赛跑,谁快用谁)。allSettled(不管死活,都要结果)。any(只要有一个活的就行)。运行机制:Promise 的回调是微任务,在同步代码执行完后、宏任务执行前执行,这涉及到了 Event Loop。最佳实践:现在项目中主要配合 async/await 使用,使异步代码看起来像同步代码,可读性更强。

1. 什么是 Promise?(核心概念)

一句话定义: Promise 是异步编程的一种解决方案,它是一个对象,代表了一个异步操作的最终完成(或失败)及其结果值。

1.1 为什么要用 Promise?

在 Promise 出现之前,我们处理异步主要靠回调函数(Callback)。当异步操作依赖另一个异步操作时,就会出现“回调地狱”(Callback Hell):

// 噩梦般的回调地狱 doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback);

Promise 的作用: 将嵌套的回调改为链式调用,解决了回调地狱问题,使代码更具可读性和逻辑性,同时提供了更好的错误处理机制。

1.2 Promise 的三种状态

Promise 是一个状态机,它拥有三种状态:

  1. Pending(进行中):初始状态,既没有被兑现,也没有被拒绝。
  2. Fulfilled(已成功/Resolved):意味着操作成功完成。
  3. Rejected(已失败):意味着操作失败。

重要特性:状态不可逆
一旦状态从 Pending 变为 Fulfilled 或 Rejected,状态就固定了,不会再发生改变。这被称为 "Settled"(已决议)。

2. Promise 的基本使用与实例方法

2.1 构造函数 (Executor)

 

const p = new Promise((resolve, reject) => { // Executor 执行器函数,是【同步执行】的! console.log('1. Executor runs immediately'); // 模拟异步 setTimeout(() => { const success = true; if (success) { resolve('Success Data'); // 状态变成 Fulfilled } else { reject('Error Reason'); // 状态变成 Rejected } }, 1000); });

面试考点: new Promise(fn) 中的 fn 是立即同步执行的。

2.2 .then(onFulfilled, onRejected)

  • 作用:接收 Promise 成功或失败的结果。
  • 返回值:返回一个新的 Promise(这是链式调用的关键)。
  • 特性
    • 如果回调函数返回一个普通值,新 Promise 状态为 Fulfilled,值为该返回值。
    • 如果回调函数抛出错误,新 Promise 状态为 Rejected。
    • 如果回调函数返回一个 Promise,新 Promise 将等待这个 Promise 的状态。
    • 值穿透:如果 .then() 没传回调函数,值会原样向后传递。

2.3 .catch(onRejected)

  • 作用:捕获 Promise 链中的错误。
  • 本质:它只是 .then(null, onRejected) 的语法糖。
  • 冒泡性:错误会沿着链一直向下传递,直到被最近的 catch 捕获。

2.4 .finally(onFinally)

  • 作用:无论 Promise 是成功还是失败,都会执行。
  • 场景:关闭 Loading 动画、关闭数据库连接等清理工作。
  • 注意:finally 不接收任何参数,它也不知道前面的状态是啥。它返回的 Promise 通常会延续上一个 Promise 的结果(除非 finally 里面抛错)。

3. Promise 静态方法 (API 详解)

这是面试中最常考察应用场景的部分。

3.1 Promise.resolve(value)

  • 作用:将现有对象转为 Promise 对象(状态为 Fulfilled)。
  • 场景:当你需要一个确定的成功结果进行后续链式调用时。

3.2 Promise.reject(reason)

  • 作用:返回一个状态为 Rejected 的 Promise 实例。

3.3 Promise.all([p1, p2, p3])

  • 逻辑"并发执行,全对才对,一错全错"
  • 输入:一个 Promise 数组(Iterator)。
  • 输出
    • 成功:当所有 Promise 都成功时,返回一个数组,包含所有结果(顺序与输入一致)。
    • 失败:只要有一个失败,立即返回那个失败的原因(短路效应)。
  • 场景:页面加载时,同时请求用户信息、菜单列表、系统配置,三个都拿到才能渲染页面。

3.4 Promise.race([p1, p2, p3])

  • 逻辑"赛跑机制,谁快听谁的"
  • 输出:返回第一个改变状态(无论是成功还是失败)的 Promise 的结果。
  • 场景
    • 请求超时控制:比如网络请求和 setTimeout 赛跑,如果 5秒没回来,setTimeout 赢了,抛出超时错误。

3.5 Promise.allSettled([p1, p2, p3]) (ES2020)

  • 逻辑"我全都要,不管对错"
  • 输出:等待所有 Promise 都结束(Settled)。返回一个数组,每个对象包含 status ('fulfilled'/'rejected') 和对应的 value 或 reason。
  • 场景:你需要知道所有请求的结果,不关心其中某个是否失败。例如批量上传图片,失败几张没关系,需要知道哪几张成功哪几张失败。

3.6 Promise.any([p1, p2, p3]) (ES2021)

  • 逻辑"只要有一个成就算成功"
  • 输出
    • 只要有一个 Promise 成功,就返回那个成功的。
    • 只有当所有 Promise 都失败时,才返回失败(AggregateError)。
  • 场景:从多个 CDN 节点加载同一张图片,只要有一个加载出来就行。

4. 进阶:Promise 与事件循环 (Event Loop)

这是区分初级和中高级开发者的分水岭。

4.1 微任务 (Microtask)

Promise 的 .then、.catch、.finally 中的回调函数属于 微任务
setTimeout、setInterval 属于 宏任务 (Macrotask)

4.2 执行顺序

  1. 执行同步代码(包括 new Promise 构造函数内部的代码)。
  2. 同步代码执行完,检查并执行所有微任务队列(Promise 回调)。
  3. 渲染 DOM(如果有必要)。
  4. 执行一个宏任务。
  5. 回到步骤 2 循环。

经典面试题:

console.log('1'); setTimeout(() => { console.log('2'); }, 0); Promise.resolve().then(() => { console.log('3'); }); new Promise((resolve) => { console.log('4'); resolve(); }).then(() => { console.log('5'); }); console.log('6');

答案与解析:
输出顺序:1 -> 4 -> 6 -> 3 -> 5 -> 2

  1. 1: 同步。
  2. setTimeout: 放入宏任务队列。
  3. 3: 放入微任务队列。
  4. 4: new Promise 是同步执行的。
  5. 5: 放入微任务队列。
  6. 6: 同步。
  7. 同步结束,清空微任务:输出 3, 5。
  8. 微任务清空,执行宏任务:输出 2。

5. 面试常见“手写”题思路

面试官可能会让你手写 Promise.all 或简易版 Promise。

5.1 手写 Promise.all

核心逻辑

  1. 返回一个新的 Promise。
  2. 遍历输入数组。
  3. 用 Promise.resolve 包装每一项(防止数组里有非 Promise 值)。
  4. 维护一个计数器 count 和结果数组 results。
  5. 每成功一个,results[i] = value,count++。
  6. 如果 count === length,调用 resolve(results)。
  7. 只要有一个失败,直接调用 reject(reason)。
Promise.myAll = function(promises) { return new Promise((resolve, reject) => { let results = []; let count = 0; if(promises.length === 0) resolve([]); promises.forEach((p, index) => { Promise.resolve(p).then(res => { results[index] = res; // 保证结果顺序和输入顺序一致 count++; if (count === promises.length) { resolve(results); } }, err => { reject(err); }) }) }) }

6. Promise 的终极形态:Async/Await

面试必问:Async/Await 和 Promise 的关系?

  • async/await 是 Generator + Promise 的语法糖
  • async 函数返回的一定是一个 Promise。
  • await 后面通常接 Promise,它会暂停 async 函数的执行,等待 Promise 解决,并把结果作为 await 表达式的值。
  • 优势:用同步的代码逻辑写异步代码,彻底解决了 .then 链过长的问题,try...catch 可以同时捕获同步和异步错误。

Read more

教育行业新机遇:用GLM-4.6V-Flash-WEB打造智能阅卷系统

教育行业新机遇:用GLM-4.6V-Flash-WEB打造智能阅卷系统 在一场全国性的中学期中考试后,某地教育局面临一个老问题:近十万份主观题试卷需要在五天内完成批改。以往靠抽调骨干教师集中阅卷的模式,不仅人力紧张、疲劳误判频发,还因评分标准执行不一引发争议。而今年,他们悄悄上线了一套基于 GLM-4.6V-Flash-WEB 的智能辅助阅卷系统——结果令人惊讶:90%的简答题实现自动评分,平均响应时间不到200毫秒,人工复核工作量减少70%,且评分一致性提升了45%。 这背后,正是多模态大模型技术向教育场景深度渗透的缩影。当AI不再只是“识别文字”,而是真正理解“学生写了什么、为什么这么写”,智能阅卷才从自动化工具迈向认知级助手。 从OCR到“类教师”理解:阅卷系统的代际跃迁 过去十年,教育科技领域的阅卷系统经历了三次迭代: * 第一代(纯OCR + 模板匹配):只能处理选择题卡或固定格式填空,对图像质量敏感,无法应对手写变体和开放性回答; * 第二代(NLP+规则引擎):引入关键词提取与句法分析,能初步判断语义相似度,但依赖大量人工编写规则,扩展性差; * 第三代(

无需代码!Fish-Speech 1.5 WebUI快速入门指南

无需代码!Fish-Speech 1.5 WebUI快速入门指南 你是否试过在深夜赶稿时,对着密密麻麻的文案发呆,只盼着有人能“念”出来帮你校对? 是否想过,只需粘贴一段文字,就能立刻生成自然、有情绪、带呼吸感的中文语音,连标点停顿都恰到好处? 不用写一行代码,不用配环境,不查文档翻到眼花——今天这篇指南,就是为你准备的。 Fish-Speech 1.5 不是又一个“参数调半天才出声”的TTS工具。它用一套真正面向使用者的设计逻辑:界面清晰、操作直觉、反馈即时、效果惊艳。尤其它的 WebUI 版本,把前沿的 DualAR 架构(双自回归 Transformer)藏在了极简按钮背后——你不需要知道什么是 VQ-GAN,也不用理解 21Hz 潜在状态映射,只要会打字、会点鼠标,就能立刻用上目前开源界语音自然度和表现力最均衡的 TTS

2025 前端年度总结:工程化落地的一年,也是前端边界被重塑的一年

2025 前端年度总结:工程化落地的一年,也是前端边界被重塑的一年

2025 年,对前端来说不是“框架年”,而是工程化深化 + AI 融合 + 跨端能力重塑的一年。 如果用一句话总结: 前端不再只是“写页面”,而是向“应用工程师 / 前端基础设施工程师”演进。 一、2025 年前端技术现状回顾 1️⃣ 框架层:Vue / React 已进入“稳定期” 2025 年,主流框架几乎没有颠覆性变化: * Vue 3:Composition API 完全成为主流 * React 18+:并发特性、Server Components 趋于成熟 * 新框架不再追求“替代”,而是补位 变化的重点不在“用不用 Vue / React”,而在于: * 是否理解响应式本质 * 是否能写可维护、可扩展的业务代码 * 是否具备工程与架构能力

苍穹外卖(前端)

苍穹外卖(前端)

前端环境搭建: 技术选型: 使用的前端技术栈:node.js、vue、ElementUI、axios、vuex、vue-router、typescript 代码结构: 核心目录 / 文件: 目录 / 文件说明apki封装 Ajax 请求的文件目录components公共组件存放目录views视图组件存放目录App.vue项目主组件、页面入口文件main.ts整个项目的入口文件router.ts路由配置文件 环境准备: 安装依赖包(生成 node_modules 目录): npm install 启动前端项目(需同时启动后端 Java 服务): npm run serve 员工管理: 员工分页查询: 需求分析和接口设计: 代码开发: 步骤一:制作页面头部 <div> <label> 员工姓名: