【问题标题】:What part of the promises/A+ spec mandates a promise must absorb state from a returned promise?承诺/A+ 规范的哪一部分要求承诺必须从返回的承诺中吸收状态?
【发布时间】:2014-03-21 01:30:54
【问题描述】:

我正在编写一个 Promise 库,我对它的部分测试套件感到困惑 (https://github.com/promises-aplus/promises-tests)。

按照这些思路进行了许多测试(为了便于阅读而进行了简化):

 var promise = new Promise();

 var done = false;
 var was_resolved = false;
 var was_rejected = false;

 promise.resolve('dummy').then(function() {
   done = true;
   return new Promise();
 });

 promise.then(
   function() { was_resolved = true; },
   function() { was_rejected = true; }
 );

 asyncAssert(function() {
   assert.true(done)
   assert.false(was_resolved);
   assert.false(was_rejected);
 });

现在,我明白了这个测试的原理;如果一个 Promise 的 resolve 函数返回一个 Promise,则吸收该 Promise 的状态(在这种情况下为待处理)。

因此,第二个 then 函数调用的回调在 Promise 自己解决之前不会被解决。

但是,仔细查看此处的规范 (http://promises-aplus.github.io/promises-spec/),我看不到任何强制执行此行为的内容。

相关点似乎是:

2.2.7 then must return a promise [[3.3](#notes)].
promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1If either onFulfilled or onRejected returns a value x, run the 
Promise Resolution Procedure [[Resolve]](promise2, x).

和:

To run [[Resolve]](promise, x), perform the following steps:
2.3.2 If x is a promise, adopt its state [[3.4](#notes)]: 

但是,如果我们仔细查看代码,我们会看到 promise 解析过程应该是:

var promise = new Promise(); <--- Promise (1)

var promise2 = promise.resolve('dummy').then(function() { <--- Promise (2)
   return new Promise(); <--- Promise (3)
 }); 

var promise4 = promise.then( <--- Promise (4)
   function() { was_resolved = true; },
   function() { was_rejected = true; }
 );

请注意,目前的“承诺堆栈”是:

- Promise 1 
-- resolve, undefined -> promise 2
-- resolve, reject -> promise 4

异步 ​​.resolve('dummy') 调用的解决方案:

[[Resolve]](1, dummy):
- 2.3.4 forfill promise (1) with 'dummy'
-- Next item on the promise stack for (1)
--- execute resolve
--- return is promise (3)
--- 2.2.7.1 run [[Resolve]](2, promise 3)
-- Next item on the promise stack for (1)
--- execute resolve 
--- return is undefined
--- 2.2.7.3 forfill promise (4) with 'dummy'

请注意,promise 2 处于待处理状态,但 promise 1 不是,因为从未在 promise 本身上调用 [Resolve]。如果 then() 返回一个 Promise,即 Promise 2,我们在 that Promise 上运行 resolve(参见规范中的 2.2.7)。

现在根据规范:

Notes 3.3 Implementations may allow promise2 === promise1, provided the implementation
meets all requirements. Each implementation should document whether it can produce 
promise2 === promise1 and under what conditions.

...但这似乎不是真的。

看起来测试套件要求在 2.2.7 中返回的 Promise 原来的 Promise,所以当 2.2.7.1 运行时,它会在自己。

如果我们在这里查看“基本”实现: https://github.com/then/promise/blob/master/core.js

我们看到 handle() 函数确实做了一些奇怪的事情,它这样做是为了履行一个承诺 p:

then() {
  ...
  return new Promise();
}

forfill(p) {
  action = pick appropriate action (p.reject or p.resolve)
  result = action()
  p.resolve(result)
}

规范不是这么说的。规范明确表示:

then must return a promise
promise2 = promise1.then(onFulfilled, onRejected);

If either onFulfilled or onRejected returns a value x,
run the Promise Resolution Procedure [[Resolve]](promise2, x).

但这似乎在做的是:

then must return a promise
promise2 = promise1.then(onFulfilled, onRejected);

If either onFulfilled or onRejected returns a value x,
run the Promise Resolution Procedure [[Resolve]](***promise1***, x).

请注意,在“参考”实现中,被调用的 onFulfilled 和 onRejected 项是与 promise1 相关联的项,而不是与 promise2 相关联的项。

也许我只是完全误解了规范的措辞?

我在这里错过了什么?

如果我正在编写 Promise 实现,我应该忽略规范并从参考示例中复制实现细节吗?

【问题讨论】:

  • 能否请您链接您所指的确切测试(您“简化”)?我只能找到github.com/promises-aplus/promises-tests/blob/master/lib/tests/…,但这完全不同。
  • @Bergi 就是这样。它做一些不同的事情吗?看起来我的简化版本对我来说是一样的。 Promise 以已解决状态进入 testPromiseResolution(在控制台上登录以检查),然后返回一个新的 Promise(deferred().promise),然后断言没有调用任何 subpromise 解析/拒绝函数?我的有什么不同?因为传入状态需要一个“虚拟”参数?
  • 糟糕,你是对的 - 我忽略了 testPromiseResolution 的作用

标签: javascript promise


【解决方案1】:

我在这里错过了什么?

一个小后缀:-)

按照这些思路进行了一些测试(为了便于阅读而进行了简化)

您似乎过于简单化了https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/2.3.2.js。它的代码更像

var promise1 = new Promise().resolve('dummy');

var promise2 = promise1.then(function() {
  return promise3 = new Promise();
}); 

var promise4 = promise2.then(
//                    ^ look here!
  function() { was_resolved = true; },
  function() { was_rejected = true; }
);

现在“promise stack”看起来像这样:

- promise 1 
-- resolve, undefined -> promise 2
- promise 2
-- resolve, reject -> promise 4

promise4 处于挂起状态,因为它依赖于 promise2,而 promise2 处于挂起状态,因为它采用了从未解决的 promise3。

如果我正在编写一个承诺实现,我应该忽略规范

没有。绝不。您绝对应该尝试理解它及其背后的原因(如果有不清楚的地方打开一个问题)。如果您不同意规范的某些部分,您仍然可能会编写不符合要求的实现,但您应该先尝试 :-)

【讨论】:

  • 很棒的作品~!试图弄清楚为什么测试会这样做真的让我很沮丧~
猜你喜欢
  • 1970-01-01
  • 2015-06-05
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 2015-11-27
  • 1970-01-01
  • 2020-12-26
  • 1970-01-01
相关资源
最近更新 更多