我正在写一个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实现,我应该忽略规范并从参考示例中复制实现细节吗?
答案 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实现,我应该忽略规范
没有。决不。你一定要试着理解它及其背后的推理(如果有什么不清楚的问题)。如果您不同意规范的某些部分,您仍然可能会编写不符合要求的实现,但您应该先尝试: - )