我正在编写一个 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 的解析函数返回 Promise,则吸收该 Promise 的状态(在本例中为待处理)。
因此,在 Promise 本身得到解决之前,第二个 then 函数调用的回调不会得到解决。
但是,仔细查看此处的规范 ( 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 堆栈”如下:
- 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,我们会对该 Promise 运行解析(请参阅规范中的 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()函数确实做了一些奇怪的事情,它这样做是为了履行 promise 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 实现,我是否应该忽略规范并从引用示例中复制实现细节?
最佳答案
What am I missing here?
一点后缀:-)
a number of tests along these lines (simplified for readability)
你似乎过于简单化了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 堆栈”如下所示:
- promise 1
-- resolve, undefined -> promise 2
- promise 2
-- resolve, reject -> promise 4
promise4 处于待处理状态,因为它依赖于promise2,而promise2 处于待处理状态,因为它采用了从 Unresolved promise3。
If I'm writing a promises implementation should I just ignore the spec
没有。绝不。您绝对应该尝试理解它及其背后的推理(如果不清楚,请提出问题)。如果您不同意规范的某些部分,您仍然可以编写不合格的实现,但您应该首先尝试:-)
关于javascript - Promise/A+ 规范的哪一部分要求 Promise 必须从返回的 Promise 吸收状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21902166/