什么时候应该使用jQuery延迟的“那么”方法,什么时候应该使用“pipe道”方法?

jQuery的Deferred有两个函数可以用来实现函数的asynchronous链接:

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacks在parsingDeferred时调用的函数或函数数组。
failCallbacks延迟被拒绝时调用的函数或函数数组。

pipe()

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

doneFilterparsingDeferred时调用的可选函数。
failFilter当Deferred被拒绝时调用的可选函数。

我知道then()已经比pipe()长了一些,所以后者必须增加一些额外的好处,但是这个差别正是我所没有的。 虽然两者的名字不同,但它们的callback参数几乎相同,返回Deferred和返回Promise的差别似乎很小。

我一遍又一遍地读了官方文档,但总是发现它们太“密集”,真的把我的头围绕着,search已经发现了很多关于这个function的讨论,但是我还没有发现任何能够真正澄清不同的东西每个的利弊。

那么什么时候使用更好,什么时候使用pipe更好呢?


加成

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

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

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

由于jQuery 1.8。然后行为与.pipe相同:

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

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

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


他们有不同的目的:

  • .then()用来处理进程的结果,也就是文档所说的,当延迟对象被parsing或拒绝时。 这与使用.done().fail()

  • 你会使用.pipe()以(预) 过滤结果。 callback到.pipe()的返回值将作为parameter passing给donefailcallback。 它也可以返回另一个延迟对象,以下callback将被注册在这个延迟。

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

所以这不是你使用.pipe() .pipe() 。 您可以使用.pipe()作为.pipe()的相同目的.then()但是逆向不成立。


例1

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

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

并且您想计算这些值的最小值和最大值。 让我们假设我们使用两个donecallback:

 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" */ }); 

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

预先提取这些值不是更好吗,这样你就不必在两个callback中单独做这个事情了。 是! 这就是我们可以使用的.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调用。 一种方法是在donecallback中进行第二次调用:

 $.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调用的callbackmakeCalls ,但

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

将不会产生预期的效果,因为第二次调用是在donecallback中进行的,而不能从外部访问。

解决方法是使用.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()您现在可以将callback附加到“内部”Ajax调用,而不会暴露调用的实际stream程/顺序。


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

没有什么情况下你必须使用then() over pipe() 。 您可以随时select忽略pipe()将传入的值。使用pipe 可能会有轻微的性能下降,但这不太可能发生。

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

这就像有一个函数返回一个永远不会被使用的值:混淆。

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

实际上,事实certificate, .pipe() .then().pipe()之间的区别被认为是不必要的,它们已经被做成和jQuery版本1.8一样。

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

在1.8中,我们将删除旧的,然后用当前的pipe道replace它。 但是非常严重的后果是,我们不得不告诉人们使用非标准的完成,失败和进展,因为提案不提供简单,有效,只是添加callback。

(emphassis矿)