承诺/ A +规范要求承诺的哪一部分必须从退回的承诺中吸收国家?

时间:2014-02-20 08:30:46

标签: javascript promise

我正在写一个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的状态(在这种情况下等待)。

因此,在自己解决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)]: 

但是,如果仔细查看代码,我们会看到承诺解决程序应该是:

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

async .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,我们在那个 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.

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

看起来testuite 要求在2.2.7中返回的承诺原始承诺,这样当运行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).

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

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

我在这里缺少什么?

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

1 个答案:

答案 0 :(得分:3)

  

我在这里缺少什么?

一个小后缀: - )

  

沿着这些方面的许多测试(为了便于阅读而简化)

您似乎过度简化了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 1 
-- resolve, undefined -> promise 2
- promise 2
-- resolve, reject -> promise 4

并且promise4正在等待,因为它依赖于promise2,因为它采用了永远不会解决的promise3。

  

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

没有。决不。你一定要试着理解它及其背后的推理(如果有什么不清楚的问题)。如果您不同意规范的某些部分,您仍然可能会编写不符合要求的实现,但您应该先尝试: - )