Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Deferred.pipe()

I've been reading about deferreds and promises in jQuery but I haven't used it yet.

I've understood everything very well but the method pipe. I really didn't get what it is.

Could some please help me to understand what it does and where could it be used?

I know there is a question titled exactly like this one (here) but its not the same. I'm asking for help to understand it and some example. The objective of the other question is to get why it doesn't work in a particular case.

like image 298
Diego Avatar asked Apr 20 '12 20:04

Diego


2 Answers

Basically, Deferred.pipe() is an asynchronous equivalent to $.map(). It projects new values from other values provided as input, but its purpose is to be used with continuations.

Let's start with an example that only requires $.each() and issues an AJAX request that returns a simple object. For each property of this object, we want the form control whose id attribute is the property's key to set its value to the property's value. We can write something like:

$.ajax("your/url", {
    dataType: "json"
}).done(function(data) {
    $.each(data, function(key, value) {
        $("#" + key).val(value);
    });
});

Now let's say we want to apply some function to the values before updating the form controls. If we do that locally, we only have to write:

$.ajax("your/url", {
    dataType: "json"
}).done(function(data) {
    $.each(data, function(key, value) {
        // doSomethingWith() projects values synchronously, as map() does.
        $("#" + key).val(doSomethingWith(value));
    });
});

But what happens if doSomethingWith() is not implemented client-side, but server-side through another web service? In that case, we want to chain the control flow into the second AJAX request, and only update the form controls when the second request has returned. Deferred.pipe() makes that easy:

$.ajax("your/url", {
    dataType: "json"
}).pipe(function(theOriginalData) {
    return $.ajax("your/web/service/doSomethingWith", {
        data: theOriginalData,
        dataType: "json"
    });
}).done(function(theFinalData) {
    $.each(theFinalData, function(key, value) {
        $("#" + key).val(value);
    });
});
like image 53
Frédéric Hamidi Avatar answered Sep 22 '22 13:09

Frédéric Hamidi


OK, I see a lot of reference material in another answer here, but reading is sometimes not the same as understanding.

I find it easiest to think of a Promise and the application of .done() to it vs. .pipe() to it. Each one acts differently. If I take promise.done(function (result) { ... }) then I can tack on more .done()'s or .fail()'s after that because each call to .done() or .fail() returns the exact same promise. So each function will be tied to the original promise and whether it gets resolved or rejected.

Now, contrast that to .pipe(). If I take promise.pipe(function (result) { ...}) then what comes out of the .pipe() is an all new promise! If I then attach .done() or .fail() to that promise then those functions will get the modified version of the results that the .pipe() returns, not the original results.

So .pipe() is, in my experience, rarely necessary. The only time it really comes in handy is if you need to modify the data that is returned from a promise before other code sees it (for example, modifying some results of an AJAX call on the client side before any other client side code works with it) or if you need to sequence things. For example, after promise A resolves or rejects, take another action, and then only when that is done do we want other code to finally trigger. All of the other code is attached to the promise B that came from the .pipe() call.

Here's a recent question where another user had problems with the use of promises and .pipe()/.done()/.when() and I tried to provide some code to clarify the use of each one in a jsFiddle: Do something when all deferreds are resolved

like image 39
John Munsch Avatar answered Sep 24 '22 13:09

John Munsch