我什么时候应该使用 jQuery deferred 的“then"?方法以及何时应该使用“管道";方法? [英] When should I use jQuery deferred's "then" method and when should I use the "pipe" method?

查看:21
本文介绍了我什么时候应该使用 jQuery deferred 的“then"?方法以及何时应该使用“管道";方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

then()

<块引用>

deferred.then( doneCallbacks, failCallbacks ) 返回:Deferred

doneCallbacks 在解析 Deferred 时调用的函数或函数数组.
failCallbacks 一个函数或函数数组,在 Deferred 被拒绝时调用.

pipe()

<块引用>

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

doneFilter 解析延迟时调用的可选函数.
failFilter 一个可选函数,当 Deferred 被拒绝时调用.

我知道 then() 的存在时间比 pipe() 长一点,所以后者必须增加一些额外的好处,但我不知道具体的区别是什么.尽管名称不同,但两者都采用几乎相同的回调参数,并且返回 Deferred 和返回 Promise 之间的区别似乎很小.

我一遍又一遍地阅读官方文档,但总是发现它们太密集"而无法真正把我的头包围,搜索发现了很多关于一个或另一个功能的讨论,但我没有找到任何真正的阐明了每种方法的不同优缺点.

那么什么时候用然后比较好,什么时候用pipe比较好?

<小时>

补充

Felix 的出色回答 确实有助于阐明这两个函数的不同之处.但我想知道是否有时 then() 的功能优于 pipe() 的功能.

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

但是有没有需要 then() 返回原始 Deferred 的用例,而 pipe() 无法做到这一点 因为它返回一个新的 Promise?

解决方案

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

<块引用>

弃用通知:从 jQuery 1.8 开始,deferred.pipe() 方法已弃用.应该使用替换它的 deferred.then() 方法.

<块引用>

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

下面的例子可能对某些人还是有帮助的.


它们有不同的用途:

  • .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) {//结果 = [{value: 2}, {value: 4}, {value: 6}]var 值 = [];for(var i = 0, len = result.length; i < len; i++) {values.push(result[i].value);}var min = Math.min.apply(Math, values);/* 用min"做一些事情*/}).then(函数(结果){//结果 = [{value: 2}, {value: 4}, {value: 6}]var 值 = [];for(var i = 0, len = result.length; i < len; i++) {values.push(result[i].value);}var max = Math.max.apply(Math, values);/* 用max"做一些事情*/});

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

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

deferred.pipe(function(result) {//结果 = [{value: 2}, {value: 4}, {value: 6}]var 值 = [];for(var i = 0, len = result.length; i < len; i++) {values.push(result[i].value);}返回值;//[2, 4, 6]}).then(函数(结果){//结果 = [2, 4, 6]var min = Math.min.apply(Math, result);/* 用min"做一些事情*/}).then(函数(结果){//结果 = [2, 4, 6]var max = Math.max.apply(Math, result);/* 用max"做一些事情*/});

显然,这是一个虚构的例子,有许多不同(也许更好)的方法来解决这个问题,但我希望它说明了这一点.


示例 2

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

$.ajax(...).done(function() {//在第一个 Ajax 之后执行$.ajax(...).done(function() {//第二次调用后执行});});

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

function makeCalls() {//这里我们返回 `$.ajax().done()` 的返回值,其中//与`$.ajax()` 单独返回的延迟对象相同返回 $.ajax(...).done(function() {//第一次调用后执行$.ajax(...).done(function() {//第二次调用后执行});});}

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

makeCalls().done(function() {//这是在第一次 Ajax 调用之后执行的});

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

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

function makeCalls() {//这里我们返回`$.ajax().pipe()`的返回值,即//一个新的延迟/承诺对象并连接到返回的对象//通过传递给 `pipe` 的回调返回 $.ajax(...).pipe(function() {//第一次调用后执行返回 $.ajax(...).done(function() {//第二次调用后执行});});}makeCalls().done(function() {//这在第二次 Ajax 调用之后执行});

通过使用 .pipe(),您现在可以将回调附加到内部"Ajax 调用而不公开调用的实际流程/顺序.


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

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

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.

I know then() has been around a little longer than pipe() so the latter must add some extra benefit, but what the difference precisely is eludes me. Both take pretty much the same callback parameters though they differ in name and the difference between returning a Deferred and returning a Promise seems slight.

I've read the official docs over and over but always find them too "dense" to really wrap my head around and searching has found lots of discussion of the one feature or the other but I haven't found anything that really clarifies the different pros and cons of each.

So when is it better to use then and when is it better to use pipe?


Addition

Felix's excellent answer has really helped clarify how these two functions differ. But I wonder if there are times when the functionality of then() is preferable to that of 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?

解决方案

Since jQuery 1.8 .then behaves the same as .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.

and

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.

The examples below might still be helpful to some.


They serve different purposes:

  • .then() is to be used whenever you want to work with the result of the process, i.e. as the documentation says, when the deferred object is resolved or rejected. It is the same as using .done() or .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 done and fail callbacks. It can also return another deferred object and 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.

So it is not that you use either .then() or .pipe(). You could use .pipe() for the same purposes as .then() but the converse does not hold.


Example 1

The result of some operation is an array of objects:

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

and you want to compute the minimum and 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 and extract the value from each object.

Wouldn't it be better to somehow extract the values beforehand 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 and there are many different (maybe better) ways to solve this problem, but I hope it illustrates the point.


Example 2

Consider Ajax calls. Sometimes you want to initiate one Ajax call after a previous one completes. One way is to make the second call inside a done callback:

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

Now lets assume you want to decouple your code and 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
        });
    });
}

You'd like to use the deferred object to allow other code which calls makeCalls to attach callbacks for the second Ajax call, but

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 and not accessible from the outside.

The solution would be to use .pipe() instead:

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

By using .pipe() you can now make it possible to append callbacks to the "inner" Ajax call without exposing the actual flow/order of the calls.


In general, deferred objects provide an interesting way to decouple your code :)

这篇关于我什么时候应该使用 jQuery deferred 的“then"?方法以及何时应该使用“管道";方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆