Promise执行器内的`resolve`和`reject`函数

4
考虑到客户端程序员既定义又使用传递给 Promise 执行器的 resolve 函数,我天真地认为我完全控制了 resolve 函数的签名,因此我可以将其定义为接受多个参数。
但是下面的代码(jsFiddle)失败了:
<html>
  <script>
   const promise = new Promise(function executor(resolve, reject) {
     setTimeout(function () {
       resolve(42, true);
       }, 1000);
   });
   promise.then(function resolveCallback(answer, howCertain) {
     console.log('callback called with arguments: ('+answer+', '+howCertain+')');
     console.log('the answer is: '+answer+'. I am '+(howCertain?'very':'not very')+' certain about that');
   });
  </script>
</html>

上述代码实际上在控制台上打印出来的内容是:
callback called with arguments: (42, undefined)
the answer is: 42. I am not very certain about that

进一步深入研究后,我写了以下代码(jsFiddle):

<html>
  <script>
   const promise = new Promise(function executor(resolve, reject) {
     console.log('entering executor, resolve is: ['+resolve+']'.);
     setTimeout(function () {
       console.log('about to call resolve');
       resolve(42);
       console.log('returning from resolve');       
       }, 1000);
   });
   console.log('about to call "then"');
   promise.then(function resolveCallback(answer) {
     console.log('the answer is: '+answer);
   });
  </script>
</html>

实际上会在控制台打印以下内容:

entering executor, resolve is: [function t() { [native code] }]
about to call "then"
about to call resolve
returning from resolve
the answer is: 42

这展示了一些有趣的事情:

  • 执行器在客户端程序员有机会调用 then 之前被调用。然而,在 executor 函数中的 resolve 参数不是 undefined
  • 在调用 then 时传递的 resolveCallback 函数与传递给 executorresolve 函数不同。此外,它不会同步执行(即不在同一事件循环运行中) executor 函数中的 resolve 调用。

Javascript 实现这个功能的唯一方法(我能想到的)是实际上插入了某种“代理”resolvereject函数,这些函数与客户端程序员提供的实际resolvereject函数异步连接。这也解释了为什么您无法为resolvereject函数定义自己的签名:因为管道工作不起来。

这个思维模型正确吗?还是我漏掉了什么?


“客户端程序员定义传递给 Promise 执行器的 resolve 函数”,不是这样的。你从哪里得到这个信息的? - Bergi
@Bergi 当我在 Promise 上调用 then 时,我不是要传递一个我选择的 resolve 函数吗?我天真地认为这与 executor 内部可用的 resolve 函数相同,但我认为这是一个合理的假设。这个实验证明了这个假设是不成立的。我只是想确认我的心理模型。 - Marcus Junius Brutus
“我所能想到的JavaScript实现这一点的唯一方法是,该实现实际上插入了某种“代理”解析和拒绝函数。显然,当调用resolve回调时,Promise对象的状态也需要从“pending”更改为“resolved”。此外,请记住您可以在同一个promise上多次调用.then(),并且所有这些回调都在promise解决时执行,这意味着它们进入Promise对象内部队列,并在调用resolve时逐个调用。” - Máté Safranka
1个回答

5

客户端程序员定义了传递给 Promise 执行器的解析函数

不,他没有(正如你的实验所证实的那样)。执行器在创建 new Promise 期间被调用。

当我在 promise 上调用 then 时,我不是传递了一个我选择的 resolve 函数吗?

不,你传递的是一个 onResolve 监听器回调,或者 实际上是一个 onFulfill 回调函数。

我的新心理模型正确吗?

是的,底层有更多的管道。

事实上,new Promise 构造函数只提供给你代理解析器函数。

Promise 包含一个状态机。它是表示异步结果的对象。因此,您可以在同一个 promise 对象上多次调用 .then(),并且回调函数始终会传递结果。

它不是对executor函数的包装,也不会像你调用then那样经常调用执行程序。执行程序只被调用一次,以使生成器可以访问解析器函数(状态机的输入)。调用then以观察状态机输出的消费者与此完全解耦-正如您所说,它们是异步地连接的。

还可以看看this。 对于您的心理模型,this是一个易于理解的Promise类实现(不保证异步和错误处理)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接