提问人:gus 提问时间:6/10/2023 最后编辑:Barmargus 更新时间:6/10/2023 访问量:91
Promise() 构造函数中的异常不应该停止脚本的其余部分吗?
Shouldn't an exception inside Promise() constructor stop the rest of the script?
问:
我正在研究构造函数,我注意到一些意想不到的事情。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'); // why does it continue?
输出:
first
inside executor
continues // whaaaaaaaaaaaaaaaaaaaaaaaat?????????
index.js:5 Uncaught (in promise) TypeError: what is not a function
at index.js:5:15
at new Promise (<anonymous>)
预期输出(我希望此输出作为执行程序
同步运行):
first
inside executor
index.js:5 Uncaught (in promise) TypeError: what is not a function
at index.js:5:15
at new Promise (<anonymous>)
构造函数据说是同步运行的,所以:executor
为什么它应该在每次异常后(之后)停止脚本的执行?continues
console.log(what();
我知道我应该使用例如 对于拒绝承诺,但这不是问题的重点。catch()
答:
4赞
trincot
6/10/2023
#1
如果它应该在每次异常后(之后)停止脚本的执行,为什么它会记录“继续”?
console.log(what();)
回调函数中发生的错误将由内部 promise 实现(即调用回调的部分)捕获,并将 promise 的状态设置为 rejected。回调的执行确实会中断,正如您对运行时错误所期望的那样。但是,当错误被捕获(处理)时,调用方将从调用中获取 promise 对象,并且执行可以愉快地继续并打印“continues”。new Promise()
请参阅 ECMAScript 规范,在 The Promise 构造函数中,executor 是触发错误的回调函数:
- 让 completion 为 Completion(Call(executor, , « resolvingFunctions.[[Resolve]],resolvingFunctions。[[拒绝]]»)).
undefined
- 如果完成是突然完成的,那么
a. 执行 ?调用(resolvingFunctions.[[拒绝]], , « 完成。[[值]]»).undefined
- 返回承诺。
错误的处理发生在步骤 10 中:请注意该过程不会进一步传播该错误,而是注册拒绝并继续执行步骤 11,这是正常完成。
我们可以想象内部promise构造函数代码看起来像这样(如果它是用JavaScript编写的),但经过简化:
class Promise {
#state
#resolvedValue
#customers
constructor(executor) {
// ... initialisation code ...
this.#state = "pending";
this.#customers = []; // Any `then`, `catch` calls would populate this
// ...
try {
executor((value) => this.#resolve(value),
(reason) => this.#reject(reason));
} catch(err) {
// Absorb the error, and allow execution to continue
this.#reject(err);
}
}
#reject(reason) {
if (this.#state !== "pending") return; // Ignore
this.#state = "rejected";
this.#resolvedValue = reason;
// Queue the asynchronous calls of any then/catch callbacks
// if they exist (registered in this.#customers)
this.#broadcast(); // I omit the implementation
}
// ... define #resolve, then, catch, #broadcast, ...
// ...
}
评论
0赞
gus
6/10/2023
因此,它的工作只是将 promise 同步“注册标记”为拒绝或适当地解析,以免影响下一个同步代码,一旦同步代码(主 JavaScript 线程)完成,它现在继续“实际”拒绝/解析 promise 按预期(已经异步),对吧?@trincotPromise()
executor
1赞
trincot
6/10/2023
你所说的“实际拒绝/解决”,实际上是通知任何“听众”已经改变的状态。我们可以认为 promise 确实是同步拒绝的,但是有了 promise,只能异步地了解状态变化。因此,只有当当前代码运行完成,使调用堆栈为空时才会发生这种情况,然后引擎将检查其队列并执行任何待处理的 / 回调以通知状态更改。then
catch
0赞
gus
6/10/2023
"我们可以认为 promise 确实是同步拒绝的,但是有了 promise,就只能异步地了解状态变化。- 这值得金子。所以,如果没有问题,被调用来解析 promise,它也会同步解析,对吧?@trincotresolve()
1赞
trincot
6/10/2023
没错,但仅靠 JavaScript 代码是无法证明这一点的,因为我们无法同步访问 promise 对象的状态。像 Chrome 的开发工具这样的控制台实现能够显示其状态(只需将 promise 对象打印到控制台即可)。观察起来可能很有趣,但无论如何,这是您在 JavaScript 代码中无法检测到的细节。我们只能听 a 或回调作为参数(或等效的参数)得到的内容。then
catch
await
1赞
trincot
6/11/2023
这意味着,如果构造函数回调中有 a,则该返回值将被忽略。这是一个应该独立于关于错误的陈述来阅读的声明。他们只列出了他们想要强调的两种行为:一种是关于错误的,另一种是关于返回值的。return 1234
评论
reject
.catch
.then
Promise()
的回调的执行是同步的,并且我们知道then()
/catch()
/finally()
的回调是异步执行的,我们将看到拒绝/解析也是异步的(在 '', '', '),因为我们没有捕获拒绝,同样的事情会发生,未经处理的拒绝是异步发生的,我认为这只是一个推论,正如你所说的那样@apokryfosfirst
inside executor
continues'