jQuery's Deferred has two functions which can be used to implement asynchronous chaining of functions:

then()

100

doneCallbacks A function, or array of functions, called when the Deferred is resolved.
failCallbacks A function, or array of functions, called when the Deferred is rejected.

pipe()

deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise

doneFilter An optional function that is called when the Deferred is resolved.
failFilter An optional function that is called when the Deferred is rejected.

我知道then()pipe()长一点,所以后者必须增加一些额外的好处,但我想不出到底有什么区别.虽然它们的名称不同,但它们都采用几乎相同的回调参数,返回Deferred和返回Promise之间的差异似乎很小.

我一遍又一遍地阅读官方文档,但总是发现它们太"密集"了,以至于我无法真正理解,搜索发现了很多关于这两个功能的讨论,但我没有发现任何东西能够真正阐明每一个功能的不同优缺点.

So when is it better to use 100 and when is it better to use 101?


Addition

Felix's excellent answer确实有助于澄清这两种功能的不同之处.但是我想知道是否有一些时候then()的功能比pipe()更好.

It is apparent that pipe() is more powerful than then() and it seems the former can do anything the latter can do. One reason to use then() might be that its name reflects its role as the termination of a chain of functions processing the same data.

But is there a use case that requires then()'s returning the original Deferred that can't be done with pipe() due to it returning a new Promise?

推荐答案

由于jQuery 1.8 .then的行为与.pipe相同:

Deprecation Notice:从jQuery1.8开始,deferred.pipe()方法已被弃用.应该使用deferred.then()方法代替它.

As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status 和 values of a deferred through a function, replacing the now-deprecated deferred.pipe() method.

下面的例子可能对一些人仍有帮助.


They serve different purposes:

  • 当您想要处理流程的结果时,即如文档所述,当延迟对象被解决或拒绝时,将使用.then().这与使用.done().fail()相同.

  • You'd use .pipe() to (pre)filter the result somehow. The return value of a callback to .pipe() will be passed as argument to the donefail callbacks. It can also return another deferred object 和 the following callbacks will be registered on this deferred.

    That is not the case with .then() (or .done(), .fail()), the return values of the registered callbacks are just ignored.

所以你用的不是either.then()or.pipe().您could.pipe()用于与.then()相同的目的,但是反之亦然.


Example 1

The result of some operation is an array of objects:

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

和 you want to compute the minimum 和 maximum of the values. Lets assume we use two done callbacks:

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" */ 

});

In both cases you have to iterate over the list 和 extract the value from each object.

Wouldn't it be better to somehow extract the values beforeh和 so that you don't have to do this in both callbacks individually? Yes! And that's what we can use .pipe() for:

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" */

});

Obviously this is a made up example 和 there are many different (maybe better) ways to solve this problem, but I hope it illustrates the point.


Example 2

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

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

Now lets assume you want to decouple your code 和 put these two Ajax calls inside a function:

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
        });
    });
}

您希望使用deferred对象来允许调用makeCalls的其他代码为second Ajax调用附加回调,但是

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

would not have the desired effect as the second call is made inside a done callback 和 not accessible from the outside.

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

function makeCalls() {
    // here we return the return value of `$.ajax().pipe()`, which is
    // a new deferred/promise object 和 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(),现在可以将回调附加到"内部"Ajax调用,而不必公开调用的实际流/顺序.


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

Jquery相关问答推荐

为什么我不能在 window.onload 事件的处理程序中将 $ jQuery 对象作为参数传递?

为什么 jQuery 不使用 requestAnimationFrame?

如何使用 jQuery 以编程方式触发对链接的点击?

JQuery 仅在 Rails 4 应用程序中的页面刷新时加载

Javascript中的选定文本事件触发器

jQuery 不会从 AJAX 查询中解析我的 JSON

如何在javascript中获取json键和值?

如果不是 jQuery,Javascript 中的美元符号是什么

$(document).on("click"... 不工作?

Rails 无法正确解码来自 jQuery 的 JSON(数组变成带有整数键的散列)

使用 jQuery 获取 div 的可见高度

如何让 twitter bootstrap 子菜单在左侧打开?

CSS3 相当于 jQuery slideUp 和 slideDown?

如何使用 jQuery 格式化电话号码

jquery分别绑定双击和单击

如何重新加载/刷新 jQuery 数据表?

在 jQuery 中 Select 后代元素的最快方法是什么?

将数据发布到 JsonP

如何使用 jQuery 的 form.serialize 但排除空字段

如何在 jquery 中获取 textarea 的值?