jQuery.Deferred.prototype.then:返回一个我不理解的行为的对象

时间:2017-12-12 20:18:37

标签: javascript jquery jquery-deferred

我一直遇到jQuery.Deferred.prototype.then的问题, 所以我决定查看jQuery的测试套件来检查我是否 正确理解这种方法的行为。 与我的问题最相关的测试如下,来自 版本3.2.1:

https://github.com/jquery/jquery/blob/3.2.1/test/unit/deferred.js#L133-L168

注意:

  • 第153行拒绝Deferred对象。
  • 在第144和164行调用
  • done。 我对QUnit并不熟悉,但它很清楚 我,测试将失败,除非 传递给done的回调实际上已执行。
  • 当且仅当done对象时,才应执行传递给Deferred的回调 已经解决,而不是被拒绝。 (这是我对Deferred的理解 documentation, 反正。)

但以上3点不可能都是正确的!

done的两次调用都是在返回的对象上进行的 jQuery.Deferred.prototype.then。我可以解释一下 代码,如果我在Promise返回的then对象中假定该代码, 最终状态与原始状态不同 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博客上,宣布新版本:

  

.then()创建的Deferred的解析状态现在由   它的回调 - 异常成为拒绝值和不可回报的回报   成为实现价值。以前,拒绝处理程序返回   成为拒绝价值观。

then的{​​{3}}尚未更新。

1 个答案:

答案 0 :(得分:2)

  

第153行拒绝延迟对象。

这是一个非常可怕的测试,一次做很多事情。有许多延迟和许多承诺,其中一些完全无关。

请注意,在第153行,defer延迟被拒绝,其中附加了.fail回调,附加了.then个回调(创建了piped)等等第153行本身附有.then个回调。

  在第144行和第164行调用

done。我对QUnit并不熟悉,但我很清楚,除非传递给done的回调实际执行,否则测试将失败。

没有。你不能混淆延迟的.done方法和QUnit完成的回调。实际上,done数组中存储了三个QUnit回调,每个回调都由assert.async()创建。

  

当且仅当Deferred对象被解析而不是被拒绝时,应该执行传递给done的回调。

是的,这正是发生的事情。请注意,第144行和第164行中的.done次调用不是针对被拒绝的defer延迟,而是针对piped承诺和.then(null, jQuery.noop)创建的另一个匿名承诺。这些承诺是被拒绝,它们是通过作为第二个参数传递给相应.then调用的onrejected回调的结果来实现的。