2 回答
那么“thenable”和“promise”这两个术语有什么区别呢?
我认为您已经引用的部分确实很好地回答了这个问题:
- thenable 是一个带有
then
方法的对象。任何物体。 - Promise是具有符合规范
then
的方法(即 thenable)的对象。
到目前为止这么简单。我认为您的实际问题是:“为什么要区分它们? ”
问题在于,通过查看一个对象,您无法确定它是否是一个承诺。
你可能会说它是一个 Promise,因为你可以看到它的then
方法是由你自己或你信任的人实现的——通常是你选择的 Promise 库。您将能够“看到”这一点,因为该对象确实从您的 Promise 原型继承,或者您甚至可以比较该方法与您定义的函数(引用地)相同。或任何其他对您来说足够的检查方法。
你可能会说它不是一个承诺,因为它没有then
方法。
但是你如何处理一个实现then
但不知道是一个承诺的对象?这是一个thenable, 并将按此处理。
Promises/A+ 规范旨在实现 promise 实现之间的互操作性,并使用鸭子类型.then()
的方法的存在。它确实指定了如何处理此类 thenables(可能是承诺或至少具有类似行为)的精确算法,以便您可以从它们创建实际的、受信任的(“已知”)承诺。
为什么它在 2 个左括号和右括号内表示?有什么约定吗?
是的,ECMAScript 规范将这种语法用于内部方法和属性:
内部属性的名称用双方括号 [[ ]] 括起来。
这些属性实际上并不需要存在,它们纯粹用于描述应该发生的事情 - 实现必须像使用它们一样行事。不过,它们是完全抽象的操作。
这是一个聪明的尝试,让 Promise 更容易在不同库之间进行互操作。
该规范thenable
仅在几个地方使用了该术语。这是最重要的(empasis mine):
承诺解决过程是一个抽象操作,将承诺和值作为输入,我们将其表示为
[[Resolve]](promise, x)
。如果 x 是 thenable,它会尝试让 promise 采用 x 的状态,假设 x 的行为至少有点像 promise。否则,它以值 x 履行承诺。
这将使实施者进行如下检查:
if (typeof(x.then) === 'function') {
// adopt the state of x
} else {
// fulfill promise with value x
}
如果规范改为说“如果 x 是一个承诺,那么......”,实施者如何知道是否x
是一个承诺?没有实用的方法可以x
仅通过检查来确定是否符合 Promise 规范。
一个实现者(比如说,图书馆FooPromises
可能会做类似的事情
if (x instanceof FooPromises.Promise) {
// adopt the state of x
} else {
// fulfill promise with value x
}
它会有效地拒绝来自不同实现的任何承诺。
相反,通过在这种情况下使用实现者可以轻松验证的超级简单的定义,thenable
进行此检查很简单,并且您可以使实现相互配合。
对于你的第二个问题,我不确定,但我的想法是符号[[Resolve]](promise, x)
强调它是一种抽象操作。如果他们去掉括号而只说Resolve(promise, x)
,这会以某种方式暗示实现者应该创建一个真正的函数Resolve
并公开它。
这不是必需的——Resolve
不是 Promise 接口的一部分;这只是他们行为的一部分,它非常重要,以至于在文档中被赋予了名称和单独的部分。