jQuery.Deferred.prototype.then: returns 一个行为我不明白的对象
jQuery.Deferred.prototype.then: returns an object with behaviour I don't understand
我在使用 jQuery.Deferred.prototype.then
时遇到了问题,
所以我决定查看 jQuery 的测试套件来检查我是否
正确理解此方法的行为。
与我的问题最相关的测试如下,来自
发布 3.2.1:
https://github.com/jquery/jquery/blob/3.2.1/test/unit/deferred.js#L133-L168
注:
Deferred
对象在第 153 行被拒绝。
done
在第 144 和 164 行被调用。
我对 QUnit 不是很熟悉,但是很清楚
我认为测试会失败,除非
传递给 done
的回调实际上被执行了。
- 当且仅当
Deferred
对象时,才应执行传递给 done
的回调
是解决了,不是拒绝了。
(这是我对 Deferred
documentation,
无论如何。)
但以上3点不可能都是正确的!
对 done
的两次调用都是针对由
jQuery.Deferred.prototype.then
。我可以解释
代码,如果我假设,在 then
返回的 Promise
对象中,
最终状态与原始状态不同
Deferred
。但是,我在 jQuery 中找不到任何提示
文档。
尽可能简短地提出我的问题:什么时候
我上面链接的代码被执行了,是回调
传递给 done
执行,如果是,为什么?
更新
这是我上面链接的代码(添加了一些注释以指示行号):
QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) {
assert.expect( 4 );
var value1, value2, value3,
defer = jQuery.Deferred(),
piped = defer.then( null, function( a, b ) {
return a * b;
} ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } );
piped.done( function( result ) { // Line 144
value3 = result;
} );
defer.fail( function( a, b ) {
value1 = a;
value2 = b;
} );
defer.reject( 2, 3 ).then( null, function() { // Line 153
assert.strictEqual( value1, 2, "first reject value ok" );
assert.strictEqual( value2, 3, "second reject value ok" );
assert.strictEqual( value3, 6, "result of filter ok" );
done.pop().call();
} );
jQuery.Deferred().resolve().then( null, function() {
assert.ok( false, "then should not be called on resolve" );
} ).then( done.pop() );
jQuery.Deferred().reject().then( null, jQuery.noop ).done( // Line 164
function( value ) {
assert.strictEqual( value, undefined, "then fail callback can return undefined/null" );
done.pop().call();
} );
} );
更新 2
事实证明,then
的行为随着 2016 年 6 月 jQuery 3 的发布而改变。
post
在 jQuery 博客上,宣布新版本:
The resolution state of a Deferred created by .then() is now controlled by
its callbacks—exceptions become rejection values and non-thenable returns
become fulfillment values. Previously, returns from rejection handlers
became rejection values.
then
的 documentation 尚未更新。
The Deferred object is rejected on line 153.
这是一个非常可怕的测试,同时做很多事情。有很多 deferred 和很多 promises,其中一些完全不相关。
请注意,在第 153 行,defer
延迟被拒绝,它确实附加了 .fail
回调,附加了 .then
回调(创建了 piped
),以及第 153 行本身附加的 .then
个回调。
done is called on lines 144 and 164. I'm not that familiar with QUnit, but it's pretty clear to me that the test will fail unless the callbacks that are passed to done are actually executed.
没有。您不能混淆延迟的 .done
方法和 QUnit 的完成回调。事实上,done
数组中存储了三个 QUnit 回调,每个回调都是由 assert.async()
.
创建的
The callbacks passed to done should be executed if and only if the Deferred object is resolved, not rejected.
是的,这正是发生的事情。请注意,第 144 行和第 164 行中的 .done
调用不是在被拒绝的 defer
延迟上进行的,而是在 piped
承诺和另一个由 .then(null, jQuery.noop)
创建的匿名承诺上进行的。这些承诺 没有 被拒绝,它们通过作为第二个参数传递给相应 .then
调用的 onrejected 回调的结果来实现。
我在使用 jQuery.Deferred.prototype.then
时遇到了问题,
所以我决定查看 jQuery 的测试套件来检查我是否
正确理解此方法的行为。
与我的问题最相关的测试如下,来自
发布 3.2.1:
https://github.com/jquery/jquery/blob/3.2.1/test/unit/deferred.js#L133-L168
注:
Deferred
对象在第 153 行被拒绝。done
在第 144 和 164 行被调用。 我对 QUnit 不是很熟悉,但是很清楚 我认为测试会失败,除非 传递给done
的回调实际上被执行了。- 当且仅当
Deferred
对象时,才应执行传递给done
的回调 是解决了,不是拒绝了。 (这是我对Deferred
documentation, 无论如何。)
但以上3点不可能都是正确的!
对 done
的两次调用都是针对由
jQuery.Deferred.prototype.then
。我可以解释
代码,如果我假设,在 then
返回的 Promise
对象中,
最终状态与原始状态不同
Deferred
。但是,我在 jQuery 中找不到任何提示
文档。
尽可能简短地提出我的问题:什么时候
我上面链接的代码被执行了,是回调
传递给 done
执行,如果是,为什么?
更新
这是我上面链接的代码(添加了一些注释以指示行号):
QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) {
assert.expect( 4 );
var value1, value2, value3,
defer = jQuery.Deferred(),
piped = defer.then( null, function( a, b ) {
return a * b;
} ),
done = jQuery.map( new Array( 3 ), function() { return assert.async(); } );
piped.done( function( result ) { // Line 144
value3 = result;
} );
defer.fail( function( a, b ) {
value1 = a;
value2 = b;
} );
defer.reject( 2, 3 ).then( null, function() { // Line 153
assert.strictEqual( value1, 2, "first reject value ok" );
assert.strictEqual( value2, 3, "second reject value ok" );
assert.strictEqual( value3, 6, "result of filter ok" );
done.pop().call();
} );
jQuery.Deferred().resolve().then( null, function() {
assert.ok( false, "then should not be called on resolve" );
} ).then( done.pop() );
jQuery.Deferred().reject().then( null, jQuery.noop ).done( // Line 164
function( value ) {
assert.strictEqual( value, undefined, "then fail callback can return undefined/null" );
done.pop().call();
} );
} );
更新 2
事实证明,then
的行为随着 2016 年 6 月 jQuery 3 的发布而改变。
post
在 jQuery 博客上,宣布新版本:
The resolution state of a Deferred created by .then() is now controlled by its callbacks—exceptions become rejection values and non-thenable returns become fulfillment values. Previously, returns from rejection handlers became rejection values.
then
的 documentation 尚未更新。
The Deferred object is rejected on line 153.
这是一个非常可怕的测试,同时做很多事情。有很多 deferred 和很多 promises,其中一些完全不相关。
请注意,在第 153 行,defer
延迟被拒绝,它确实附加了 .fail
回调,附加了 .then
回调(创建了 piped
),以及第 153 行本身附加的 .then
个回调。
done is called on lines 144 and 164. I'm not that familiar with QUnit, but it's pretty clear to me that the test will fail unless the callbacks that are passed to done are actually executed.
没有。您不能混淆延迟的 .done
方法和 QUnit 的完成回调。事实上,done
数组中存储了三个 QUnit 回调,每个回调都是由 assert.async()
.
The callbacks passed to done should be executed if and only if the Deferred object is resolved, not rejected.
是的,这正是发生的事情。请注意,第 144 行和第 164 行中的 .done
调用不是在被拒绝的 defer
延迟上进行的,而是在 piped
承诺和另一个由 .then(null, jQuery.noop)
创建的匿名承诺上进行的。这些承诺 没有 被拒绝,它们通过作为第二个参数传递给相应 .then
调用的 onrejected 回调的结果来实现。