前端 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

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

VR音游音符轨道系统开发实录与原理解析 在 VR 音游的开发过程中,音符轨道系统是最核心的交互与可视化部分。本文结合一次完整的开发实录,分享从核心原理与设计到VR内容构建的完整过程,帮助读者快速理解音符轨道系统的实现思路。 文章目录 * VR音游音符轨道系统开发实录与原理解析 * 一、实录结果 * 二、VR内容开发步骤 * 1. 准备音符与交互逻辑 * 2. 创建谱面 * 3. 绘制音轨 * 4. 预制件与音频替换 * 三、原理解析(音符轨道系统) * 1. 音符轨道(Note Track) * 2. 轨迹调节与偏移控制 * 3. 音符触摸激活 * 4. 谱面编辑工具(Editor 功能) * 四、总结与展望 * 1. 成果回顾:从零到一的核心突破 * 2. 技术总结:核心设计理念 * 3. 开发难点与问题反思 * 4. 优化策略与改进方向 * 5.

OpenClaw配置Bot接入飞书机器人+Kimi2.5

OpenClaw配置Bot接入飞书机器人+Kimi2.5

上一篇文章写了Ubuntu_24.04下安装OpenClaw的过程,这篇文档记录一下接入飞书机器+Kimi2.5。 准备工作 飞书 创建飞书机器人 访问飞书开放平台:https://open.feishu.cn/app,点击创建应用: 填写应用名称和描述后就直接创建: 复制App ID 和 App Secret 创建成功后,在“凭证与基础信息”中找到 App ID 和 App Secret,把这2个信息复制记录下来,后面需要配置到openclaw中 配置权限 点击【权限管理】→【开通权限】 或使用【批量导入/导出权限】,选择导入,输入以下内容,如下图 点击【下一步,确认新增权限】即可开通所需要的权限。 配置事件与回调 说明:这一步的配置需要先讲AppId和AppSecret配置到openclaw成功之后再设置订阅方式,

FPGA中XDMA多通道传输架构:全面讲解

FPGA中XDMA多通道传输架构:实战解析与工程优化 从一个真实问题说起:为什么我的FPGA数据传不快? 你有没有遇到过这样的场景: FPGA采集了一路4K视频流,每秒要往主机内存送超过1.5GB的数据;同时还要接收来自CPU的控制指令,比如调整曝光、切换模式。结果发现—— 视频帧延迟越来越高,控制命令还经常丢包 。 查PCIe带宽?没问题,Gen3 x8理论有7.8 GB/s,远超需求。 看CPU负载?也不高,不到20%。 那问题出在哪? 答案往往是: 数据通路设计不合理,没有用好XDMA的多通道能力 。 很多工程师把所有数据都塞进一个H2C或C2H通道里,导致高优先级的控制流被大块数据“堵”在后面。这就像让救护车和货车挤同一条车道,再宽的马路也会瘫痪。 本文将带你深入Xilinx XDMA(Xilinx Direct Memory Access)IP核的多通道机制,不仅讲清楚“它是怎么工作的”,更聚焦于 如何在实际项目中高效使用它 ——从寄存器配置到软件编程,从性能调优到常见坑点,全部基于一线开发经验展开。 XDMA是什么?

(10-1)大模型时代的人形机器人感知:视觉-语言模型在机器人中的应用

(10-1)大模型时代的人形机器人感知:视觉-语言模型在机器人中的应用

本章内容聚焦大模型时代人形机器人的感知体系升级,系统介绍了视觉—语言模型、多模态Transformer与3D大模型在机器人中的核心作用,详细讲解了文本、视觉、点云与语音等信息的语义对齐与融合机制,介绍了从语言指令到视觉目标的Grounding、任务分解与意图理解方法,并通过闭环感知与决策联动,展示了大模型支撑机器人在复杂真实场景中的理解、规划与实时行动的用法。 10.1  视觉-语言模型在机器人中的应用 视觉—语言模型(Vision-Language Model,VLM)通过统一建模视觉与自然语言,使机器人具备“看懂并理解语言”的能力,是大模型时代机器人感知与认知融合的核心技术。VLM不仅能够完成图像识别、目标检测等传统感知任务,还可以直接理解语言指令、进行语义推理,并将高层语义映射为可执行的感知与行动目标,在人形机器人中广泛应用于交互理解、场景认知和任务执行等环节。 10.1.1  CLIP/BLIP/Flamingo等模型简介 随着大规模多模态数据与Transformer架构的发展,视觉—语言模型逐渐从“跨模态对齐”演进为“多模态理解与推理”。CLIP、BLIP与Flam