什么时候应该使用jQuery延迟的“then”方法,何时应该使用“管道”方法?

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

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

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

pipe()

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

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

我知道then()已经比pipe()长了一些,所以后者必须增加一些额外的好处,但是其中的差别正是我所没有的。 虽然它们的名称不同,但它们都采用几乎相同的回调参数,返回Deferred和返回Promise之间的区别似乎很小。

我一遍又一遍地阅读官方文档,但总是发现它们太“密集”,真的把我的头围绕着,搜索已经发现了很多关于这个功能或其他功能的讨论,但是我没有找到任何能够真正阐明它们的不同之处每个的利弊。

因此,当是它更好地使用then ,当是它更好地使用pipe


加成

菲利克斯的出色答案确实有助于澄清这两种功能的不同之处。 但是我想知道then()的功能是否优于pipe()

显而易见的是, pipe()是更强大的比then()似乎前者可以做任何事情,后者可以做。 使用then()一个原因可能是它的名字反映它的作用是终止处理相同数据的函数链。

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


既然jQuery 1.8 .then行为与.pipe相同:

弃用声明:从jQuery 1.8开始,不推荐使用deferred.pipe()方法。 应该使用代替它的deferred.then()方法。

从jQuery 1.8开始deferred.then()方法返回一个新的promise,它可以通过函数过滤延迟的状态和值,替代现在不推荐使用的deferred.pipe()方法。

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


他们有不同的目的:

  • .then()用于处理流程结果的任何时候,也就是文档所说的,当延迟对象被解析或拒绝时。 它与使用.done().fail()

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

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

  • 因此,它是不是您使用.then().pipe() 你可以使用.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调用。 一种方法是在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 ,但

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

    将不会产生预期的效果,因为第二次调用是在done回调中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调用,而不会暴露调用的实际流程/顺序。


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


    没有任何情况下你必须使用then() over pipe() 。 您始终可以选择忽略pipe()传入的值。使用pipe可能会有轻微的性能下降 - 但这不太可能发生。

    所以看起来你可能总是在两种情况下总是使用pipe()但是 ,通过使用pipe() ,您正在与其他读取代码的人(包括您自己,从现在开始六个月)进行交流,以确定返回值具有一定的重要性。 如果你放弃它,你就违反了这个语义结构。

    这就像有一个函数返回一个永远不会使用的值:令人困惑。

    所以在你应该的时候使用then()当你应该使用pipe()时...


    实际上,事实证明, .pipe() .then().pipe()之间的区别被认为是不必要的,它们已经被做成与jQuery 1.8版本相同。

    来自jaubourg在jQuery bug跟踪器票#11010“MAKE DEFERRED.THEN == DEFERRED.PIPE LI PROMISE / A”中的评论:

    在1.8版中,我们将删除旧版本,然后将其替换为当前管道。 但是非常严重的后果是,我们必须告诉人们使用非标准的完成,失败和进度,因为提案并不提供简单,有效,只是添加回调的意思。

    (emphassis矿)

    链接地址: http://www.djcxy.com/p/55317.html

    上一篇: When should I use jQuery deferred's "then" method and when should I use the "pipe" method?

    下一篇: Options added to a <select> are invisible in the list box on iPhone