jquery - 什么时候应该使用jQuery deferred的 "then"方法,什么时候应该使用 "pipe"方法?

标签 jquery asynchronous jquery-deferred decoupling jquery-chaining

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

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

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 之间的区别似乎很小。

我一遍又一遍地阅读官方文档,但总是觉得它们太“密集”,无法真正理解,搜索发现有很多关于一个功能或另一个功能的讨论,但我没有找到任何真正阐明了各自的优缺点。

那么什么时候使用then比较好,什么时候使用pipe比较好?


加法

Felix's excellent answer确实有助于阐明这两个功能的不同之处。但我想知道是否有时 then() 的功能优于 pipe()

很明显 pipe()then() 更强大,而且似乎前者可以做后者可以做的任何事情。使用 then() 的一个原因可能是它的名称反射(reflect)了它作为处理相同数据的函数链的终止的作用。

但是是否有一个用例需要 then() 返回原始的 Deferredpipe() 无法完成 因为它返回了一个新的 Promise

最佳答案

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

Deprecation Notice: As of jQuery 1.8, the deferred.pipe() method is deprecated. The deferred.then() method, which replaces it, should be used instead.

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

下面的示例可能对某些人仍然有帮助。


它们有不同的用途:

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

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

    .then()(或.done().fail())不是这种情况,返回值的已注册回调将被忽略。

所以不是你使用或者 .then() 或者 .pipe()。您可以.pipe() 用于与 .then() 相同的目的,但反过来不成立。


示例 1

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

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

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

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

});

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

事先以某种方式提取值,这样您就不必在两个回调中分别执行此操作,这不是更好吗?是的!这就是我们可以将 .pipe() 用于:

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 调用。一种方法是在 done 回调中进行第二次调用:

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

不会产生预期的效果,因为第二次调用是在 done 回调中进行的,无法从外部访问。

解决方案是使用 .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(),您现在可以将回调附加到“内部”Ajax 调用,而无需公开调用的实际流程/顺序。


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

关于jquery - 什么时候应该使用jQuery deferred的 "then"方法,什么时候应该使用 "pipe"方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9583783/

相关文章:

javascript - 使用 Javascript 选择菜单 onChange DIV 元素

jquery - 在移动设备上将 Bootstrap 布局从内联表单更改为网格

c# - 有没有办法将观察者订阅为异步

javascript - 如何*何时*延迟数组

javascript - Nester在循环中延迟了Ajax调用

javascript - 如何跨多个函数处理 Promise?

jquery - 我可以用什么来代替 :indeterminate jQuery selector to avoid an exception in IE 8?

javascript - 如何根据th更新td?

java - 没有从测试用例中调用 Spring DeferredResult onCompletion

scala - 检查 Future[Boolean] 的结果是 true 还是 false