1

I have read many threads here and am trying to understand callbacks and deferred etc. Basically the History of it.

What I mean is let's say I have 3 functions

function Primary() {console.log('Primary')};
function Secondary() {console.log('Secondary')};
function College() {console.log('College')};
  • How would I call them one after the other?
  • Are Callbacks the only way to do so before Deferred was introduced?
  • What are the disadvantages of Callbacks that would prompt me to move my code to using Deferred objects?

To me what I understood is that deferred is an easy way to manage multiple callbacks. But I am not able to relate it with an example so that I can compare and decide. How and why is it easy?

How does Promises come into the picture?

One important bit that I forgot to add and Richard guessed correctly is that I need the result of the first function in the next one

Thomasmkov
  • 59
  • 7
  • 7
    If there's no async code in the functions, just call them in order: `Primary(); Secondary(); College();` – ahren Nov 12 '13 at 15:09
  • Ok I removed the non-ajax bit. I am new to this Q&A so was just focusing on the callbacks vs deferred part. – Thomasmkov Nov 12 '13 at 15:13
  • There are plenty of SO questions explaining it: http://stackoverflow.com/questions/6801283/what-are-the-differences-between-deferred-promise-and-future-in-javascript http://stackoverflow.com/questions/14127703/asynchronous-javascript-callbacks-vs-deferred-promise – ahren Nov 12 '13 at 15:14
  • `I need the result of the first function in the next one` - the answer he gave doesn't do that. This is sinful, but will do that - `College(Secondary(Primary()));` – Reinstate Monica Cellio Nov 12 '13 at 15:45

1 Answers1

1

If I'm reading this correctly, you're asking how to chain these functions so that they execute as callbacks to each other, and then what the purpose of moving that to a deferred/promise model would be? To call these as callbacks, you'd first have to change the way you write those functions, so that they each execute a callback:

function Primary(callback) {
    console.log('Primary');
    if (typeof callback === 'function') {
        callback();
    }
}
function Secondary(callback) {
    console.log('Secondary');
    if (typeof callback === 'function') {
        callback();
    }
};
function College(callback) {
    console.log('College');
    if (typeof callback === 'function') {
        callback();
    }
};

Now you can call each of these by passing them as callbacks to 1 function call, like so:

Primary(function () {
    Secondary(College);
});

You're calling the Primary function, and passing an anonymous function callback to be executed from within Primary. That function will call Secondary, and pass College as its callback to execute internally. The problem with this, which promises help to mitigate, is that for deep callback chains, you get this sideways Christmas tree of nested callbacks, which is ugly and difficult to read. You can restructure this some, using promises, like so:

function Primary() {
    console.log('Primary');
    return $.Deferred().resolve().promise();
};
function Secondary() {
    console.log('Secondary');
    return $.Deferred().resolve().promise();
};
function College() {
    console.log('College');
    return $.Deferred().resolve().promise();
};

And now you can just call your function chain like this:

Primary()
    .then(Secondary)
    .then(College);

Now you have one nice chain of execution, which is easily readable, and each one executes as soon as the previous one finishes. We return a promise object from each function, which is used to chain the next function call from, and we're immediately resolving them within the functions, because there's no asynchronous logic going on here. You can read a pretty good article about promises themselves here.

Edit: To ugly it up a little more, just to demonstrate that sideways tree look some more, here you go, Archer :D

Primary(function () {
    Secondary(function () {
        College();
    });
});

And for an example of how to pass the value of one into the next using the traditional callback mathodology, for user2983762, here's an example of that implementation. Note: This implementation is specific to the use case listed. For an arbitrary nesting of functions with optional callbacks that may receive the value of the previous function call, it becomes more difficult with this model, because functions may return functions, so it's hard to tell whether that function is received as a callback or a value at any generic point:

function Primary(callback) {
    var returnVal = true;
    console.log('Primary');
    if (typeof callback === 'function') {
        callback(returnVal);
    }
}
function Secondary(val, callback) {
    var returnVal = false;
    console.log('Secondary');
    if (typeof callback === 'function') {
        callback(returnVal);
    }
};
function College(val) {
    console.log('College');
    if (typeof callback === 'function') {
        callback();
    }
};
Primary(function (primaryVal) {
    Secondary(primaryVal, function (secondaryVal) {
        College(secondaryVal);
    });
});

This would call Primary, passing our anonymous function to be fired as a callback, which receives primaryVal, and in turn, calls Secondary, passing another anonymous function, which receives secondaryVal, and in turn, calls College, passing secondaryVal to it. Under a deferred object model, this becomes a lot easier to handle, as well as to abstract, like so:

function Primary(receivedVal) {
    var returnVal = true;
    console.log('Primary');
    return $.Deferred().resolve(returnVal).promise();
};
function Secondary(receivedVal) {
    var returnVal = false;
    console.log('Secondary');
    return $.Deferred().resolve(returnVal).promise();
};
function College(receivedVal) {
    var returnVal = {};
    console.log('College');
    return $.Deferred().resolve(returnVal).promise();
};

In this case, we don't have to alter our execution chain at all. Each time we resolve one of these functions and pass a returnVal to it, it's automatically passed into the next callback as receivedVal, in a nice, generic fashion.

  • Richard that you so much for understanding my problem. I know I explained it badly but you got it right! – Thomasmkov Nov 12 '13 at 15:41
  • That makes using deferred a lot more appealing than callbacks. You also need to change the callback example so that you execute `College` in an anonymous function, in order to pass a callback into that as well. Go on - make it even uglier :D – Reinstate Monica Cellio Nov 12 '13 at 15:43
  • Can you cook up an example to show how to use the 3 functions in callback where B() needs the value of A() and C() needs the value of B() – Thomasmkov Nov 12 '13 at 15:44