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

注:

但以上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.

thendocumentation 尚未更新。

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 回调的结果来实现。