【问题标题】:jQuery.Deferred.prototype.then: returns an object with behaviour I don't understandjQuery.Deferred.prototype.then:返回一个行为我不明白的对象
【发布时间】:2017-12-12 20:18:36
【问题描述】:

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 执行的,如果是,为什么?

更新

这是我在上面链接的代码(添加了一些 cmets 来指示行号):

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 的解析状态现在由 它的回调——异常变成拒绝值和不可返回的返回 成为履行价值。以前,从拒绝处理程序返回 变成了拒绝值。

thendocumentation 尚未更新。

标签: javascript jquery jquery-deferred


【解决方案1】:

Deferred 对象在第 153 行被拒绝。

这是一个非常可怕的测试,一次做很多事情。有许多 deferred 和许多 promise,其中一些完全不相关。

请注意,在第 153 行,defer deferred 被拒绝,它确实附加了一个 .fail 回调,附加了 .then 回调(它创建了 piped),以及更多 .then 回调附加在第 153 行自己。

在第 144 行和第 164 行调用了 done。我对 QUnit 不太熟悉,但我很清楚,除非实际执行传递给 done 的回调,否则测试将失败。

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

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

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

【讨论】:

  • 关于“存储在 done 数组中的三个 QUnit 回调”:是的,我完全理解这一点。我没有困惑。关于你的最后一段:这是我需要的答案。我在“更新 2”中的帖子中添加了补充信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 2011-09-14
相关资源
最近更新 更多