
promise 构造函数内部的同步执行器(executor)中抛出的异常会被 Promise 机制捕获并处理,将 Promise 的状态设置为 rejected,但不会立即中断后续脚本的执行。这是因为 Promise 内部已经对异常进行了处理,避免了程序崩溃,允许后续代码继续运行。本文将深入探讨这一机制,并提供示例代码进行说明。
在学习 Promise 构造函数时,可能会遇到一个看似违反直觉的现象:在 new Promise() 内部的执行器函数中抛出异常,程序并没有立即停止,而是继续执行了后续的代码。
例如以下代码:
console.log('first'); const promise1 = new Promise((resolve, reject) => { console.log('inside executor'); let what = 1 console.log(what()); console.log('not reached'); resolve('Hi Guys!'); }); console.log('continues'); // 为什么会继续执行?
这段代码的输出结果是:
first inside executor continues Uncaught (in promise) TypeError: what is not a function at index.JS:5:15 at new Promise (<anonymous>)
可以看到,尽管 what() 导致了 TypeError 异常,但 console.log(‘continues’) 仍然被执行了。 这背后的原因在于 Promise 内部对异常的处理机制。
Promise 的异常处理机制
Promise 构造函数接收一个执行器函数(executor)作为参数。 这个执行器函数会立即同步执行。如果执行器函数内部抛出了异常,Promise 内部会捕获这个异常,并将 Promise 的状态设置为 rejected。 重要的是,这个捕获和状态变更是在 Promise 内部完成的,不会直接中断外部代码的执行。
根据 ecmascript 规范,Promise 构造函数的具体步骤如下:
- 创建一个新的 Promise 对象。
- 调用执行器函数,并传入 resolve 和 reject 两个函数作为参数。
- 如果执行器函数执行过程中抛出了异常,则调用 reject 函数,并将异常作为参数传递给它。
- 返回新创建的 Promise 对象。
关键在于,即使执行器函数抛出了异常,Promise 构造函数仍然会正常返回 Promise 对象,而不会立即中断后续代码的执行。
模拟 Promise 内部实现
为了更好地理解 Promise 的异常处理机制,我们可以简单地模拟 Promise 构造函数的内部实现:
class MyPromise { #state #resolvedValue #customers constructor(executor) { this.#state = "pending"; this.#customers = []; try { executor((value) => this.#resolve(value), (reason) => this.#reject(reason)); } catch(err) { this.#reject(err); } } #reject(reason) { if (this.#state !== "pending") return; this.#state = "rejected"; this.#resolvedValue = reason; this.#broadcast(); } }
在这个模拟实现中,try…catch 块捕获了执行器函数中可能抛出的异常,并调用 #reject 方法将 Promise 的状态设置为 rejected。 即使发生了异常,constructor 函数仍然会正常返回。
如何处理 Promise 的 rejected 状态
虽然 Promise 内部捕获了异常,但我们仍然需要处理 Promise 的 rejected 状态。 通常使用 .catch() 方法或者 async/await 结构中的 try…catch 块来处理。
例如:
console.log('first'); const promise1 = new Promise((resolve, reject) => { console.log('inside executor'); let what = 1 console.log(what()); console.log('not reached'); resolve('Hi Guys!'); }).catch(error => { console.error("Promise rejected:", error); }); console.log('continues');
或者使用 async/await:
async function myFunction() { console.log('first'); try { const result = await new Promise((resolve, reject) => { console.log('inside executor'); let what = 1 console.log(what()); console.log('not reached'); resolve('Hi Guys!'); }); console.log("Promise resolved:", result); } catch (error) { console.error("Promise rejected:", error); } console.log('continues'); } myFunction();
总结
Promise 构造函数内部的执行器函数中抛出的异常不会立即中断后续脚本的执行,这是因为 Promise 内部对异常进行了捕获和处理。为了处理 Promise 的 rejected 状态,我们需要使用 .catch() 方法或者 async/await 结构中的 try…catch 块。 这种机制使得 Promise 能够更好地处理异步操作中的异常,避免程序崩溃。


