4

I'm hoping to understand why I'm getting different behavior when attemping to chain a deferred object directly than I do when attempting to chain by saving the object in a variable and invoking one or more deferred methods on that variable.

When saving the object in a variable, the value sent in to each function is the same (in the case of the code snippet below, 5) - i.e. the values don't filter in this case. When chained directly, the values filter... so I'm unclear on how get filtering to occur when setting up a Deferred.pipe() in several different statements. And by my reading of the jquery docs, it should be possible:

The Deferred object is chainable, similar to the way a jQuery object is chainable, but it has its own methods. After creating a Deferred object, you can use any of the methods below by either chaining directly from the object creation or saving the object in a variable and invoking one or more methods on that variable.

What am I doing wrong?

Here is my code:

<script type="text/javascript">
$(document).ready(function () {
// This works as expected - alert(20)

var defer = new $.Deferred();
defer.pipe(myFunction).pipe(myFunction).pipe(myAlert);
defer.resolve(5);

// This does not work as expected - alert(5)
var defer2 = new $.Deferred();
defer2.pipe(myFunction);
defer2.pipe(myFunction);
defer2.pipe(myAlert);
defer2.resolve(5);

});

var myFunction = function (value) {
return value * 2;
}

var myAlert = function (value) {
alert('The value is ' + value);
}
</script>
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
AndrewH
  • 43
  • 3
  • It's likely that some operations return a new promise (like `.pipe()`) so chaining would operate on the newly returned object. – jfriend00 Sep 19 '12 at 00:31

2 Answers2

3

The $.Deferred object is indeed chainable, but in your second scenario, you are not chaining anything; you are just assigning multiple pipes to the $.Deferred object to be executed independently, when the $.Deferred is either resolved or rejected. In other words, you are ignoring the returned Promise object which contains the filtered/modified value to be passed to the next .pipe() in the chain.

From the docs:

The deferred.pipe() method returns a new promise that filters the status and values of a deferred through a function.

To achieve what you want in your second example, pipe the resulting Promise instead of the original $.Deferred object:

var defer2 = new $.Deferred();
var promise = defer2.pipe(myFunction);
promise = promise.pipe(myFunction); // pipe and update promise
promise.pipe(myAlert);
defer2.resolve(5);

DEMO.

João Silva
  • 89,303
  • 29
  • 152
  • 158
  • Thank you. So in the case of pipe(), it's literal. :) I accept that, even though it's inconsistent with the documentation I cited above. Here's the challenge - I don't know how many pipe() calls I'll need to make, so I'm wondering if there is a clean way to chain a variable number of functions together and still get the filtering behavior (using pipe() or otherwise). – AndrewH Sep 19 '12 at 00:51
  • @AndrewH: Yes, there is, store each intermediate `Promise` object, and keep piping it. Here's an example: http://jsfiddle.net/kU9nz/. It's the exact same idea as yours, but by piping through the returned `Promise` object. – João Silva Sep 19 '12 at 00:55
-1

Joao, I had the same case - unknown number of pipe to be called. here is how do that - Asynchronous for cycle in JavaScript

Community
  • 1
  • 1