Promise知识点回顾

Promise缺点。

1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。

当创建一个新的Promise时, 传递给Promise构造函数的执行器函数(executor function)会被立即调用。 这代表Promise代表的异步操作实际上已经开始, 而不是等待某个条件或延迟。这就是立即执行的意思
resolve/reject 这个函数调用本身是同步执行的,它立即将Promise的内部状态从pending 变为 fulfilled(或rejected),并保存值,然后检查是否通过.then()注册了回调函数。 如果有回调:引擎不会立即执行这些回调,而是创建一个微任务(microtask),将这些回调放入到微任务队列;微任务队列会在当前执行栈清空后、下一个宏任务开始前被依次同步处理。
严格来说:resolve 本身并不在微任务中执行,它只是触发将then 回调排入微任务队列的动作。回调函数的执行才是真正发生在微任务中的。

js 复制代码
    const executor = (resolve, reject) => {
       console.log('执行器内代码');
       resolve('完成');
    };
    const p = new Promise(executor);
 
    // promise 内部构造函数如下:
    function Promise (executor){
      try {
        executor(resolve, reject);
      } catch (err) {
        reject(err);
      }
    }
  // 所以Promise构造函数的 executor 参数是立即执行的,是同步执行的, 无法在它运行之后再去"取消"

2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

如果不设置回调函数 (.catch或 .then的第二个参数)内部抛出的错误不会反应到外部。 即使 try...catch; 错误会被吞噬,(仅表现为未处理的rejection 警告);

arduino 复制代码
 promise的错误处理机制:Promise 内部的错误(包括执行器函数中的 throw 或 reject)
 会被Promise内部捕获并转化为rejected 状态; 如果没有.catch 或.then的第二个参数处理这个rejection,
 那么该错误就会被"吞没", 不会冒泡到外部同步代码 try...catch 
 
js 复制代码
  (async () => {
      try {
        await new Promise((resolve, reject) => {
           throw new Error('内部错误'); // 或者 reject('内部错误')
        });
      } catch (err) {
        console.log('捕获到:', err);
      }
    })();
   //这种方式可以捕获到同步错误
   try...catch 包裹 new Promise 无法捕获内部抛出的错误, 因为Promise构造函数
   内部已经将错误捕获并转换为rejection。
   如果错误是在then回调中抛出的, 且没有.catch, 同样会被吞没。

原因在于: Promise内部已经自己拦截了错误(无论通过throw 还是reject),并将它转换为rejected状态。外层的 try...catch 只能捕获同步代码执行过程中的即时抛出的错误;而Promise内部的错误是异步传递的。所以完全绕过了外层的 try...catch**"异步处理" 指的是:Promise 内部发生的错误(无论是同步 throw 还是 reject)不会被立即向外抛出,而是被转换为一个 rejected 状态的 Promise,其错误处理回调(如 .catch)会在当前调用栈清空后的微任务阶段执行。** 这种从"同步抛出"到"微任务处理"的转变,就是异步性的核心体现。

3 .第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise对象的错误传递

1. Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止。

如果某个Promise rejected, 会沿着链式调用传递到下一个catch;
Promise 内部构造函数内部 会try...catch 执行器函数的同步错误,一但捕获到就会调用内部的reject函数将错误转为rejected 状态,这是向后传递的起点。executor中抛出的错误被捕获后并没有被吞掉,而是通过reject()传递给了Promise对象, 然后该Promise对象的rejected状态就会沿着链传递到下一个catch
异步回调中抛出错误(setTimeout 里 throw)无法被Promise 捕获,甚至会导致程序崩溃;没有外层的try...catch 会直接抛出到全局;
then 回调是微任务,并且Promise要求实现必须用 try...catch 包裹每个回调;所以同步错误会被转化为 rejection
setTimeout 回调时宏任务,由事件循环直接调用;没有外层的try-catch 因此会直接抛出到全局环境; 效果图

在Promise的onFulfilled 或onRejected 中 任何同步抛出的值(无论是显式 throw 还是隐式的运行时异常)都会导致返回的新Promise 变为rejected;

js 复制代码
//1.  运行时错误,这种属于隐式的抛出错误;
Promise.resolve({})
  .then(obj => {
    obj.a.b;   // 抛出 TypeError
  })
  .catch(err => {
    console.log('捕获到:', err); // 输出:TypeError: Cannot read property 'b' of undefined
  });
// 2. 显式抛出错误;
throw new Error('xxx'); 
// 两者行为完全一致,都是抛出一个错误对象(或任意值)。
// Promise的机制不关系错误是 显式throw的还是 隐式运行时产生的,
// 它只关心在回调执行过程中是否有未捕获的异常被抛出; 只要有,都会转化为rejected

// 3. 语法报错 不会进入回调;因为脚本在解析阶段就失败了;
Promise.resolve().then(() => {
  if(true {return 1}
})
js 复制代码
throw new Error(123) 与 new Erro(123) 的区别
1. throw new Error(123) 会抛出异常,中断当前函数执行
2. new Erro(123) 仅仅创建了一个Error对象实例,不会产生任何副作用,程序继续执行;(不影响后续代码,因为没抛出)

PromiseA 、PromiseA+ 、 ES6 Promise 之间的关系

PromiseA

  • 提出者:CommonJS 社区
  • 地位与作用:该领域的早期规范,奠定了Promise的核心概念(如状态机、then方法),但部分细节定义模糊
  • 局限性与评价: 作为"开路先锋",它为后来的标准指明了方向,但其自身并不算完美;

PromiseA+

  • 提出者:社区开发者(基于Promise/A的改进)
  • 地位与作用:事实上的行业标准。它严格定义了 .then()链式调用的核心机制(称为thenable),并提供了详尽的兼容性测试套件
  • 局限性与评价:作为一个"最小化规范", 它只关心then方法,并未规定如何创建Promise实例; 也没有定义catch、finally, all 等便捷方法

ES6规范(官方标准)

  • 提出者:ECMA国际组织(TC39委员会)
  • 地位与作用:JS语言的官方标准,实现了Promise的大统一
  • 局限性与评价:完全遵守Promise/A+的核心then行为,确保与各类Promise库互相操作。同时不起了catch,finally, all, race 等全套API

简单来说:Promise/A+ 是对Promise/A 的改进和完善, 而ES6 Promise又全盘采纳了Promise/A+的行为准则。

js 复制代码
什么是thenable 
指的是任何拥有then方法的对象或函数。简单来说只要一个东西又.then方法,就是thenable; 
它是Promise生态中实现互操作性的基石。让来自不同库的异步对象能够无缝协作。ES6 Promise完全遵循这一设计;
// 这是一个 thenable 
const thenable = {
  then: function(onFulfilled, onRejected) {
      
  }
}
// 这也是一个thenable 
function foo () {}
foo.then = function(onFulfilled) { onFulfilled(42) };
// Promise/A+ 规范没有规定如何创建Promise(留给具体实现), 但是规定了一个同意的互操作机制,
// 任何Promise实现(ES6 Promise、 BlueBird、 Q、 $q等)都应该能无缝处理其他库返回的thenable

具体来说:
Promise.resolve(value) 如果遇到一个thenable, 不会直接把它当作普通值包装,
而是展开它:调用它的then 方法,并把自己的状态绑定到该thenable的结果上。
这样不同的Promise库之间可以互相消费对方返回的 类Promise对象。实现兼容;
const qPromise = Q.delay(100).then(() => 'done');
Promise.resolve(qPromise).then(val => {
  console.log(val); // 'done'
});

Promise 链返回值规则

js 复制代码
1. then/catch 返回一个新Promise
2. 回调返回值决定新Promise 状态。
   返回普通值-> resolved,值传递下去
   返回Promise -> 新Promise跟随该Promise的状态  
   抛出异常(或返回rejected Promise)-> rejected,  错误传递下去

Promise 错误传递机制

js 复制代码
1. 链中任一环节的rejection 会向后传递, 直到遇到第一个catch 或then的失败回调;
2. catch本质是 then(null, onRejected)
3. 若未捕获,最终触发unhandledrejection 事件;
相关推荐
行走的陀螺仪4 小时前
JavaScript 算法详解:10大经典算法,通俗易懂,从入门到精通
开发语言·javascript·算法
拓荒牛儿4 小时前
前端内存可观测实践
前端
yqcoder4 小时前
异步的魔法:深入解析 async/await 原理与编译本质
前端·javascript
iiiiyu4 小时前
面向对象和集合编程题
java·开发语言·前端·数据结构·算法·编程语言
taocarts_bidfans5 小时前
2026跨境SaaS工具选型指南:Taoify与Shopify/Shopyy/Ueeshop深度对比
java·前端·javascript·跨境电商·独立站
环信5 小时前
环信Flutter UIKit适配鸿蒙实战指南
前端
秋秋20235 小时前
做了个 AI 对话页面才发现,流式渲染没想象中那么简单
前端·aigc
环信5 小时前
HarmonyOS Flutter 键盘高度监听插件开发完全指南
前端
真夜5 小时前
开发正常但生产异常的 Bug:Vite manualChunks 循环依赖导致 ReferenceError
前端·前端框架·vite