JavaScript Promise 的正确术语是什么?

24

我对各种术语感到困惑。据我理解,Promise 可以是:

  • 已完成
  • 已拒绝
  • 待定
  • 已解决
  • 已解决
  • 延迟

“已解决”是指已经“已完成”吗?还是说它已经被“已解决”了?而“延迟”到底是什么意思?


2
不幸的是,这个术语并没有被一致地使用。特别是,太多人使用“resolved”来表示“已实现”。您可能会发现这个链接有用:https://dev59.com/12Ml5IYBdhLWcg3wmn04#18295163 - user663031
2
在选择这些术语时,浪费了一个运用“renege”一词的绝佳机会。 - Magnus Lind Oxlund
3个回答

67

术语可能很难理解。
让我们从Promises/A+规范相应的ES6章节中了解到,有3种状态

  • pending - 承诺尚未获得值,其结果仍不确定。
  • fulfilled - 承诺成功地获得了结果值“分配”
  • rejected - 承诺被给予一个原因,说明无法获得结果,通常是一个错误。

术语settled是fulfilled和rejected的总称,意思是-与pending相反。

动态动词fulfillreject描述了将状态从pending更改为fulfilled或rejected。这些转换称为承诺的fulfillmentrejection

这些都很简单。现在,resolve 是一个不同的问题。它有时被用作“履行”的同义词,但更好地理解为将承诺的命运解决为已实现或已拒绝。承诺的解决(很少:解决)意味着它离开了待定状态。但即使如此也不准确——问题在于Promise Resolution Procedure的递归性质:

  • 使用“普通”值解决承诺意味着实现它

  • 使用承诺(或可解决对象)解决承诺意味着采用其状态:

    • 使用已实现的承诺解决是实现
    • 使用已拒绝的承诺解决是拒绝
    • 使用待定的承诺解决意味着等待其解决

是的,如果承诺得到解决,甚至可能不知道它是否会被实现或拒绝。但它意味着命运不再未定,因为它与我们解决的承诺相关联——请注意,您只能解决一次承诺,不能通过再次调用resolve/reject将其解决为不同的值。

忽略这种特殊情况,一个已解决的 Promise 通常意味着一个已经处理了的 promise。

或者引用 ECMAScript 6规范

如果 Promise 已经被"锁定"以匹配另一个 promise 的状态,则该 Promise 被认为是已解决的。尝试解决或拒绝一个已解决的 Promise 没有任何效果。如果 Promise 没有被解决,则它始终处于等待状态。已解决的 Promise 可能处于等待、已实现或已拒绝状态。

state diagram with transitions


“什么是defer?” 推迟结果意味着你返回一个(异步)承诺来代替直接返回结果(同步)。并且会返回一个延迟的拒绝而不是同步抛出异常。 注意,一些库(Q)中也使用“defer”作为构造Deferred对象的方法名 - 参见this answer on The differences between Deferred, Promise and Future以获取更好的解释。 噢,千万不要信任变量名: defer 可能同样是“deferredObject”的缩写。

2
typo: hyperonym → hypernym - kYuZz
2
视觉效果非常有帮助,但如果明确指出“待处理”包括“已解决”中未包含在“已解决”中的部分,则会更加有帮助。目前情况下,它给人的印象是“待处理”和“已解决”是互斥的,这与 ECMA 规范的引用相矛盾。 - LarsH
1
可能令人困惑的是,在大多数情况下,“resolve”只意味着“实现或匹配另一个promise的状态”。例如,对于非thenable值,Promise.resolve(..)new Promise((resolve, _) => {resolve(..)})只会创建一个已实现的promise,而不会创建一个被拒绝的promise。然而,对于非promise thenable的不寻常情况,它可以拒绝或实现(即解决)。因此,“解决或匹配另一个promise的状态”实际上是正确的。 - mdcq
1
如果你用一个字符串来解决一个 Promise,那么它会立即被该字符串完成。它永远不会被拒绝。只有当你用另一个 Promise(或 thenable)来解决一个 Promise 时,它的最终命运可能是未知的。@GeorgeMeijer - Bergi
1
是的,在这里,“plain”意味着“非thenable/非promise”。 - Bergi
显示剩余13条评论

13

三种 Promise 状态在 Promises/A+ 规范的 2.1 节 中列出。

来自规范:

enter image description here

以下是您所询问的每个术语:

Pending 是初始的承诺状态。代表承诺的操作尚未被履行或拒绝。

Fulfilled 是另外三种承诺状态之一。它意味着承诺已经解决并且现在具有其解决值。代表承诺的操作已成功完成。

Rejected 是另外三种承诺状态之一。它意味着承诺已被拒绝并且现在具有其拒绝原因。代表承诺的操作未能获得值,因此有一个失败的原因(通常是错误代码或错误对象,但可以是任何内容)。

Settled 是一个术语,表示承诺已经被兑现或拒绝(例如,它不再是待定状态),但它不是一个单独的状态,只是一个描述性术语,用于指示它不再是待定状态。

已解决是一个经常用来表示与已实现相同的术语,但两者并不完全相同。承诺可以通过一个值得到解决,这会导致实现,也可以通过拒绝的承诺(这会导致该承诺被拒绝)或者可以通过挂起的承诺(这意味着它现在将等待某些其他承诺的最终状态)得到解决。

很难确切地说出你所说的延迟是什么意思。承诺通常被归类为延迟对象,因为它们是代表将来推迟执行的操作和结果的对象(它将在未来发生)。在一些承诺的实现中,实际上有两种类型的对象,即延迟对象和承诺对象。延迟对象是承诺对象的超集。两者都可以使用.then()处理程序观察操作何时被解决或拒绝。但是,只有延迟对象可以实际更改状态为已解决已拒绝

在jQuery中,您可以使用$.Deferred()创建延迟对象。在其他实现中,例如ES6 promises,您只需使用具有构造函数回调的promise对象,该回调具有rejectresolve函数。世界可能正在朝着ES6的方向发展。
以下是使用deferred对象的jQuery示例:
function delay(t) {
    var defer = $.Deferred();
    setTimeout(function() {
        defer.resolve();
    }, t);
    return defer.promise()
 }

 delay(200).then(function() {
     // run my delayed function now
     doMyThing();
 });

ES6 Promise 示例:

 function delay(t) {
     return new Promise(function(resolve, reject) {
         setTimeout(function() {
             resolve();
         }, t);
     });
 }

 delay(200).then(function() {
     // run my delayed function now
     doMyThing();
 });

他们不喜欢你引用规范。/s - Millie Smith
@MillieSmith - 是的,尽管我喜欢并使用MDN作为一个有用的资源,但这次它似乎把承诺状态搞错了,所以我认为直接去规范是明智的选择。 - jfriend00
@jfriend00:请看我的回答,澄清解析和履行之间的区别。尽管您的描述不够准确,但并不至于被踩 :-) - Bergi
@Bergi - 好的,我整理了一下术语描述。 - jfriend00

1
Domenic Denicola的"状态与命运"是一个简明扼要的总结。
状态:
- 如果`promise.then(f)`将尽快调用f,则承诺已经被履行。 - 如果`promise.then(undefined, r)`将尽快调用r,则承诺已被拒绝。 - 如果承诺既没有被履行也没有被拒绝,则它处于待定状态。
命运:
- 如果尝试解决或拒绝承诺没有任何效果,即该承诺已被“锁定”以遵循另一个承诺,或者已被履行或拒绝,则该承诺已解决。 - 如果未解决,则该承诺未被解决,即尝试解决或拒绝它将对该承诺产生影响。
有关“状态和命运”的详细信息,请点击链接。

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