【发布时间】: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