异步 - 我应该何时使用jQuery deferred的“then”方法,何时应该使用“pipe”方法?

jQuery的then()有两个函数可用于实现函数的异步链接:

then()

then()

doneCallbacks解析Deferred时调用的函数或函数数组。
failCallbacks拒绝延迟时调用的函数或函数数组。

then()

then()

doneFilter解析Deferred时调用的可选函数。
failFilter拒绝Deferred时调用的可选函数。

我知道then()已经比Deferred稍微长一点,所以后者必须增加一些额外的好处,但正是这种差异恰恰在于我。 两者都采用了几乎相同的回调参数,尽管它们的名称不同,返回pipe()和返回Promise之间的区别似乎很小。

我一遍又一遍地阅读官方文档但总是发现它们很密集" 为了真正包围我的头脑,搜索已经找到了很多关于这个特征或其他特征的讨论,但我还没有发现任何真正澄清每个特征的不同利弊的东西。

那么什么时候使用then()更好,何时使用Deferred更好?


加成

菲利克斯的出色答案确实有助于澄清这两个功能的区别。 但我想知道是否有时候then()的功能优于Deferred

显然then()Deferred更强大,看起来前者可以做后者可以做的任何事情。 使用pipe()的一个原因可能是它的名称反映了它作为处理相同数据的函数链终止的作用。

但有没有一个用例要求then()返回原来的Deferred 2479411822064040010由于它返回新的Promise而无法完成?

3个解决方案
102 votes

由于jQuery 1.8 makeCalls的行为与.pipe()相同:

弃用通知:自jQuery 1.8起,不推荐使用makeCalls方法。 应该使用替换它的.pipe()方法。

从jQuery 1.8开始,makeCalls方法返回一个新的promise,它可以过滤通过函数延迟的状态和值,替换现在已弃用的.pipe()方法。

以下示例可能对某些人有所帮助。


它们用于不同的目的:

  • 只要您想要处理过程的结果,即文档说明,当解决或拒绝延迟对象时,将使用makeCalls。 与使用.pipe().pipe()相同。

  • 您以某种方式使用makeCalls(预)过滤结果。 回调到.pipe()的返回值将作为参数传递给.pipe().then()回调。 它还可以返回另一个延迟对象,并且将在此延迟上注册以下回调。

    makeCalls(或.pipe(),.pipe())不是这种情况,注册回调的返回值只是被忽略。

因此,不是您使用makeCalls.pipe().您可以将.pipe()用于与.then()相同的目的,但反过来不成立。


例1

某些操作的结果是一个对象数组:

[{value: 2}, {value: 4}, {value: 6}]

并且您想要计算值的最小值和最大值。 让我们假设我们使用两个makeCalls回调:

deferred.then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var min = Math.min.apply(Math, values);

   /* do something with "min" */

}).then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var max = Math.max.apply(Math, values);

   /* do something with "max" */ 

});

在这两种情况下,您都必须遍历列表并从每个对象中提取值。

以某种方式预先提取值是不是更好,这样你就不必单独在两个回调中做到这一点? 是! 这就是我们可以使用的makeCalls

deferred.pipe(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    return values; // [2, 4, 6]

}).then(function(result) {
    // result = [2, 4, 6]

    var min = Math.min.apply(Math, result);

    /* do something with "min" */

}).then(function(result) {
    // result = [2, 4, 6]

    var max = Math.max.apply(Math, result);

    /* do something with "max" */

});

显然这是一个组成的例子,有许多不同的(可能更好的)方法来解决这个问题,但我希望它说明了这一点。


例2

考虑Ajax调用。 有时您希望在前一个Ajax调用完成后启动一个Ajax调用。 一种方法是在makeCalls回调中进行第二次调用:

$.ajax(...).done(function() {
    // executed after first Ajax
    $.ajax(...).done(function() {
        // executed after second call
    });
});

现在让我们假设您想要解耦代码并将这两个Ajax调用放在函数中:

function makeCalls() {
    // here we return the return value of `$.ajax().done()`, which
    // is the same deferred object as returned by `$.ajax()` alone

    return $.ajax(...).done(function() {
        // executed after first call
        $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

您希望使用延迟对象来允许调用makeCalls的其他代码为第二个Ajax调用附加回调,但是

makeCalls().done(function() {
    // this is executed after the first Ajax call
});

因为第二次调用是在.pipe()回调中进行的,并且无法从外部访问,所以不会产生预期的效果。

解决方案是使用.pipe()代替:

function makeCalls() {
    // here we return the return value of `$.ajax().pipe()`, which is
    // a new deferred/promise object and connected to the one returned
    // by the callback passed to `pipe`

    return $.ajax(...).pipe(function() {
        // executed after first call
        return $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

makeCalls().done(function() {
    // this is executed after the second Ajax call
});

通过使用.pipe(),您现在可以将回调附加到&#34;内部&#34; Ajax调用时不暴露实际的调用流/顺序。


通常,延迟对象提供了一种有趣的方法来解耦代码:)

Felix Kling answered 2019-08-13T18:54:48Z
6 votes

没有必须使用then()超过pipe()的情况。您可以随时选择忽略pipe()传入的值。使用pipe可能会有轻微的性能损失 - 但这不太重要。

因此,在这两种情况下,您似乎总是可以使用then()。 但是,通过使用pipe(),您正在与读取您的代码的其他人(包括您自己,六个月后)沟通,以确定返回值的重要性。 如果你放弃它,你就违反了这种语义结构。

它就像有一个函数返回一个从未使用过的值:令人困惑。

所以当你应该使用then()时,你应该使用pipe() ......

Alex Feinman answered 2019-08-13T18:55:38Z
5 votes

实际上,事实证明jaubourg.pipe()之间的差异被认为是不必要的,并且它们已经与jQuery版本1.8相同。

来自jaubourg的评论jQuery的错误跟踪器票#11010&#34; MAKE DEFERRED.THEN == DEFERRED.PIPE LIKE PROMISE / A&#34;:

在1.8中,我们将删除旧的然后用当前管道替换它。 但非常麻烦的结果是,我们必须告诉人们使用非标准的完成,失败和进步,因为该提议并不提供简单,有效,意味着只需添加回调。

(强调我的)

hippietrail answered 2019-08-13T18:56:28Z
translate from https://stackoverflow.com:/questions/9583783/when-should-i-use-jquery-deferreds-then-method-and-when-should-i-use-the-pip