【问题标题】:how does promise resolution decide whether to treat a return value as a promise or as a plain value?承诺解析如何决定是将返回值视为承诺还是纯值?
【发布时间】:2025-11-28 00:15:02
【问题描述】:

根据 resolve() 的返回值或传递给 then() 的函数的返回值是否是 Promise,Promise 解析“有帮助”会做不同的事情。

因此,理解和预测行为需要准确地知道正在使用(或允许使用)什么标准来确定某事是否“是一个承诺”,因为我在上面的句子中使用了这个短语,所以我想把它确定下来。我对 Promises/A+ 感兴趣,尤其是 ES6 原生 Promise。

看着https://promisesaplus.com/,它说:

1.1 "promise" is an object or function with a "then" method
    whose behavior conforms to this specification.

为了了解这意味着什么,我进一步研究了 2.2 “The then 方法”,发现它依赖于一组 行为标准显然不可能通过算法决定给定对象是否 是不是一个承诺(由停止问题证明)。没关系;它只是意味着规范 有问题的“有用”行为不会直接使用“是一个承诺”这个词。

因此,进一步寻找“有用”行为的规范,我找到了 2.3“承诺解决程序”。 惊喜!它确实直接使用了“是一个承诺”这个词:

2.3.2 If x is a promise, adopt its state [3.4]

但它使自己免于在脚注中陷入无意义:

[3.4] Generally, it will only be known that x is a true promise
      if it comes from the current implementation. This clause allows
      the use of implementation-specific means to adopt the state of
      known-conformant promises.

换句话说,2.3.2 并不是真的意味着“如果 x 是一个承诺”,它真的意味着(并且应该说,IMO)“如果 x 已知是一个承诺”。

但是,如果我理解正确的话,那部分只是一个捷径,它可以证明这样做是安全的。 继续前进,相关部分似乎是 2.3.3,我总结为:将返回值 x 视为承诺 如果 x 有一个名为“then”的属性,它是一个函数。

那么这一切都取决于“x.then 是一个函数”的定义。 确切地说,对于想要实现符合标准的库的人来说,这意味着什么, 或者有人想预测一个符合标准的库在我使用它时必须/可能做什么? 和typeof x.then === "function"一样吗?

希望获得更多线索,我查看了一个所谓符合标准的实现(或一组实现)的规范,ES6 原生承诺, 链接自 MDN 上的 Promises 文档。 我相信相关部分是25.4.1.3.2。 看起来有问题的标准是 IsCallable(x.then);按照链接到那个, 令我沮丧的是 IsCallable 不是一个实际的函数,而是一个“抽象操作”, 用许多其他远非简单的“抽象操作”来定义。

在这一点上,我希望看到任何实现相关决定的符合参考代码的希望似乎正在迅速消退:-(

支持我最初的问题“承诺解决方案如何决定是否将返回值视为承诺?”, 我认为我已经把它归结为更具体的问题,正如我上面解释的:当 Promises/A+ 规范说“是一个函数”时,它到底是什么意思?

如果有一个简单明确的答案(当然这可能会在实现之间留出空间), 立即跟进的问题是:

  • 原生 Promise 是否符合简单明确的答案?
  • 为什么原生 promises 对 promises/A+ 的“是一个函数”的实现如此复杂?
  • 什么是我的合理方式来确保我的返回值将被视为我打算的承诺, 还是按照我的意图作为一个简单的值?

【问题讨论】:

  • '当 Promises/A+ 规范说“是一个函数”时,它到底是什么意思?' - 绝对与 ECMA 规范相同 - “可以作为子例程调用的对象类型的成员”ecma-international.org/ecma-262/6.0/…

标签: javascript promise es6-promise


【解决方案1】:

那么这一切都取决于“x.then 是一个函数”的定义。什么意思,和说typeofx.then === "function"一样吗?

是的,正是如此。除非访问 x.then 会抛出异常,因此您需要将所有这些都包装在 try 块中。

为什么原生promise的promise/A+的“是一个函数”的实现这么复杂?

因为它是规范术语。 "function" 基本上被定义为“可调用对象”,isCallable 只是用于测试的算法。与typeof operator判断是否返回字符串"function"的算法基本相同。


顺便说一句,你会对Regarding Promises/A+ Specification, what is the difference between the terms "thenable" and "promise"?感兴趣。

【讨论】:

  • 你是说 IsCallable 等价于 'typeof x.then === "function"' 吗?在您引用的三个部分中,我没有看到任何说明这一点的内容。您能否在 ES 规范中提供任何支持证据,说明它们是相同的,和/或证明 'typeof x.then === "function"' 是 Promises/A+ 规范打算谈论的条件?感谢您的链接,是的,这很有趣。
  • @DonHatch:是的,这就是我要说的。我无法进一步证明“implements”与“has the method”的含义相同,并且我无法引用任何解释 Promises 措辞的明确参考资料/A+ 任何进一步,但我确实知道这是预期的。您还可以检查任何用 JS 编写的 Promise 实现,或任何需要 isCallable 的 polyfill - 它们都使用 typeof
  • 当你说你“知道这是预期的”时,我假设你只是在谈论 Promises/A+ 规范(而不是 ES 问题)——在这种情况下,好吧,这是可信的,因为 Promises/A+ 规范是用松散的语言编写的。至于 ES 规范的 isCallable 是否等同于“typeof ... === 'function'”,我真的很难相信如此重要的等价性,而没有说明或从规范中明确证明。我想实现使用 typeof 的事实就是证据,但如果规范甚至没有暗示它,我的上帝,这将是多么荒谬的浪费。
  • @DonHatch 实际上你可以让它指代两者,我确实知道很多东西 :-) 每个规范只是按照惯例建立了某些东西。很少有文件声明他们使用英语或what certain English phrases mean。 ES 不是用机器可读的语言编写的(您可以使用定理证明器来建立等价性),但是这种特殊的等价性虽然没有明确指出,但定义得很好(它既不重要,也不有趣,也不容易理解)。相比之下,例如 ES 根本没有说明 OOP 是如何工作的……
  • 嗯...这有点超现实,但我不得不说我非常不同意你关于它不重要的断言,你关于它不有趣的断言... ,最重要的是,您断言它不容易理解:如果他们在谈论的时候使用他们定义的术语“isCallable”,那将是非常清楚的...... if 正如您所声称的,当他们定义 typeof == "function" 应该做什么时,这就是他们真正的意思。如果您的说法属实,那么规范的这一部分肯定看起来像是一堆乱七八糟的词,完全无法沟通。
最近更新 更多