🧠 深入理解 JavaScript Promise 与 `Promise.all`:从原型链到异步编程实战

在现代 JavaScript 开发中,Promise 是处理异步操作的核心机制之一。ES6 引入的 Promise 极大地简化了"回调地狱"(Callback Hell)问题,并为后续的 async/await 语法奠定了基础。而 Promise.all 则是并发执行多个异步任务并统一处理结果的强大工具。

本文将结合 原型链原理Promise 基础用法实际示例代码 ,带你系统掌握 Promise 及其静态方法 Promise.all 的使用与底层逻辑。


🔗 一、JavaScript 的面向对象:原型链而非"血缘"

在深入 Promise 之前,我们先厘清一个关键概念:JavaScript 的继承不是基于"类"的血缘关系,而是基于原型(prototype)的链式查找机制

1.1 🏗️ 构造函数与原型对象

ini 复制代码
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.speci = '人类';

let zhen = new Person('张三', 18);
console.log(zhen.speci); // 输出: "人类"
  • Person 是构造函数。
  • Person.prototype 是所有 Person 实例共享的原型对象。
  • zhen.__proto__ 指向 Person.prototype
  • Person.prototype.constructor 又指回 Person,形成闭环。

🚂 小比喻 :可以把 constructor 看作"车头",prototype 是"车身"。实例通过 __proto__ 连接到车身,而车身知道自己的车头是谁。

1.2 ⚡ 动态修改原型链(不推荐)

ini 复制代码
const kong = {
    name: '孔子',
    hobbies: ['读书', '喝酒']
};

zhen.__proto__ = kong;
console.log(zhen.hobbies);     // ✅ 输出: ['读书', '喝酒']
console.log(kong.prototype);   // ❌ undefined!普通对象没有 prototype 属性

⚠️ 注意:

  • 只有函数 才有 prototype 属性;
  • 普通对象(如 kong)只有 __proto__,没有 prototype
  • 在这里kong是object的一个实例kong.__prpto__ == object.prototype

💡 虽然可以动态修改 __proto__,但会破坏代码可预测性,影响性能,应避免使用。


⏳ 二、Promise:ES6 的异步解决方案

2.1 🧩 Promise 基本结构

xml 复制代码
<script>
const p = new Promise((resolve, reject) => {
    console.log(111); // 同步执行
    setTimeout(() => {
        console.log(333);
        // resolve('结果1');  // 成功
        reject('失败1');      // 失败
    }, 1000);
});

console.log(222);
console.log(p, '////////'); // 此时 p 状态仍是 pending
console.log(p.__proto__ == Promise.prototype); // true
</script>

📋 执行顺序分析:

  1. 111 立即输出(executor 函数同步执行)✅
  2. 222 紧接着输出 ✅
  3. p 此时处于 pending(等待) 状态 ⏳
  4. 1 秒后,333 输出,调用 reject('失败1'),状态变为 rejected
  5. .catch() 捕获错误,.finally() 无论成功失败都会执行 🔁

2.2 🎯 Promise 的三种状态

  • ⏳ pending:初始状态,既不是成功也不是失败。
  • ✅ fulfilled :操作成功完成(通过 resolve 触发)。
  • ❌ rejected :操作失败(通过 reject 触发)。

🔒 核心特性 :一旦状态改变,就不可逆。这是 Promise 的设计基石。

2.3 🔍 原型关系验证

javascript 复制代码
console.log(p.__proto__ === Promise.prototype); // ✅ true
  • pPromise 的实例。
  • 所有 Promise 实例的 __proto__ 都指向 Promise.prototype
  • Promise.prototype 上定义了 .then(), .catch(), .finally() 等方法。
  • Promise.prototype.__proto__ == object.prototype

🚀 三、Promise.all:并发处理多个异步任务

3.1 ❓ 什么是 Promise.all

Promise.all(iterable) 接收一个可迭代对象(如数组),其中包含多个 Promise。它返回一个新的 Promise:

  • ✅ 全部成功 → 返回一个包含所有结果的数组(顺序与输入一致)。
  • ❌ 任一失败 → 立即 rejected,返回第一个失败的原因。

3.2 💻 使用示例

javascript 复制代码
const task1 = fetch('/api/user');       // 假设返回 { id: 1, name: 'Alice' }
const task2 = fetch('/api/posts');      // 假设返回 [{ title: 'JS' }]
const task3 = new Promise(resolve => setTimeout(() => resolve('done'), 500));

Promise.all([task1, task2, task3])
  .then(([user, posts, msg]) => {
    console.log('全部完成:', user, posts, msg);
  })
  .catch(err => {
    console.error('某个任务失败:', err);
  });

🌐 适用场景:需要同时加载用户信息、文章列表、配置数据等,全部就绪后再渲染页面。

3.3 ⚠️ 错误处理演示

ini 复制代码
const p1 = Promise.resolve('成功1');
const p2 = Promise.reject('失败2');
const p3 = Promise.resolve('成功3');

Promise.all([p1, p2, p3])
  .then(results => console.log('不会执行'))
  .catch(err => console.log('捕获错误:', err)); // 输出: "失败2"

关键点 :只要有一个失败,整个 Promise.all 就失败,其余成功的 Promise 结果会被丢弃。

3.4 🛡️ 替代方案:Promise.allSettled(ES2020)

如果你希望无论成功失败都等待所有任务完成 ,可以使用 Promise.allSettled

javascript 复制代码
Promise.allSettled([p1, p2, p3])
  .then(results => {
    results.forEach((res, i) => {
      if (res.status === 'fulfilled') {
        console.log(`✅ 任务${i} 成功:`, res.value);
      } else {
        console.log(`❌ 任务${i} 失败:`, res.reason);
      }
    });
  });

✅ 适用于:批量上传、日志收集、非关键资源加载等场景。


📚 四、总结:从原型到实践

概念 说明
🔗 原型链 JS 对象通过 __proto__ 查找属性,constructor 指回构造函数
Promise 表示异步操作的最终完成或失败,具有 pending/fulfilled/rejected 三种状态
🧩 Promise.prototype 所有 Promise 实例的方法来源(.then, .catch 等)
🚀 Promise.all 并发执行多个 Promise,全成功则成功,任一失败则整体失败
🛡️ 最佳实践 使用 Promise.all 提升性能;用 allSettled 处理非关键任务

💭 五、思考题

  1. 🤔 为什么 console.log(p)setTimeout 之前打印时,状态是 pending
  2. 🛠️ 能否通过修改 Promise.prototype.then 来全局拦截所有 Promise 的成功回调?这样做有什么风险?
  3. 📦 如果 Promise.all 中传入空数组 [],结果会是什么?

💡 答案提示

  1. 因为异步任务尚未执行,状态未改变。
  2. 技术上可行,但会破坏封装性、可测试性和团队协作,强烈不推荐
  3. 立即 resolved,返回空数组 [] ------ 这是符合规范的!

通过本文,你不仅掌握了 PromisePromise.all 的用法,还理解了其背后的 原型机制异步执行模型。这将为你编写健壮、高效的异步代码打下坚实基础。🌟

Happy Coding! 💻✨

相关推荐
jingling55520 小时前
Mark3D | 用 Mars3D 实现一个炫酷的三维地图
前端·javascript·3d·前端框架·html
前端白袍20 小时前
Vue:如何实现日志导出下载功能?
javascript·vue.js·ecmascript
这是个栗子20 小时前
【前端知识点总结】请求/响应拦截器的介绍
前端·拦截器
Y‍waiX‍‍‮‪‎⁠‌‫‎‌‫‬20 小时前
【npm】从零到一基于Vite+vue3制作自己的Vue3项目基础的npm包并发布npm
前端·npm·node.js
专注VB编程开发20年20 小时前
vb.net宿主程序通过统一接口直接调用,命名空间要一致
服务器·前端·.net
2503_9284115620 小时前
12.18 中后台项目-权限管理
前端·javascript·数据库
Y‍waiX‍‍‮‪‎⁠‌‫‎‌‫‬20 小时前
NRM-NPM的镜像源管理工具使用方法
前端·npm·node.js
hssfscv20 小时前
JAVAweb学习笔记——JS
javascript·笔记·学习
茶憶21 小时前
UniApp 安卓端实现文件的生成,写入,获取文件大小以及压缩功能
android·javascript·vue.js·uni-app
未来之窗软件服务1 天前
一体化系统(九)智慧社区综合报表——东方仙盟练气期
大数据·前端·仙盟创梦ide·东方仙盟·东方仙盟一体化