15

I understand the idea of a callback, where I pass a function into another function and that function then uses the supplied function at will.

I am struggling to understand deferred callbacks, even after googling it.

Could someone provide a simple explanation please? I program in Ruby, but also know C/C++ a bit, but most of all I was a experienced assembly language programmer. So I am wondering is it a bit like a stack of callback addresses that get pop'd? I am hoping to learn jquery or node.js and these deferred callbacks seem integral to both. I understand basic threading principles (though mutex object makes my head hurt ;)

5
  • Do you mean jQuery's Deferred objects? Is is this about something specific to Node.js?
    – bfavaretto
    Apr 9, 2012 at 13:54
  • 1
    No I mean in general. Though I do want to learn jquery and possibly node.js, I felt that I needed to get a handle on what a deferred callback actually is first. I read the Wikipedia article on callbacks, but I could not get an understanding of deferred callbacks, which seem intrinsic to the paradigm of asynchronous operation that will be involved in these languages that use it.
    – tentimes
    Apr 9, 2012 at 13:59
  • stackoverflow.com/questions/4869609/…
    – c69
    Apr 9, 2012 at 14:36
  • 1
    I am really asking for the conceptual idea of deferred callback as opposed to their implementation - sorry if I did not make that more clear. I gave language examples more to explain the idea that I am trying to clarify and also my programming background so people would know how to pitch the answer. Thanks very much for the answers so far - I am getting there!
    – tentimes
    Apr 9, 2012 at 15:20
  • Ok I think I have got it now folks, thanks to you all! I don't know what way to do the answer though. Cameron explained the concept most simply and that was what I was really after, but others also chimed in and added to my knowledge. I am not sure what way to accept the answer as I am new to this ;)
    – tentimes
    Apr 9, 2012 at 17:27

5 Answers 5

4

By request, here are comments presented as an answer:


I'm not sure you completely grok the fact that functions in JS are first-class objects, and can therefore be stored until needed, past the time they are created.

For example, say you want to write to a file, then print out a log message; so you call the "write()" function (or whatever) and pass it a function that outputs the log message (this is the deferred callback function). "write()" internally stores a reference to the given function, starts writing to the file, and sets up its own callback to know when the write is finished. It then returns before the write is done; when it is, the internal callback is somehow called (this is the underlying framework's job -- in the case of node.js, it's done with an event loop), which then calls your callback which prints the log message.

The "deferred" part simply means that your callback function isn't called right away; calling it is deferred until the appropriate time. In the case of asynchronous functions like many of those in node.js, the given callback is generally called when the operation completes (or an error occurs).

Most stuff is async in node.js, but in the browser with e.g. jQuery, most stuff is actually synchronous (except, obviously, for AJAX requests). Since first-class functions are so handy in JavaScript (especially because of great closure support), callbacks are used everywhere in the browser too, but they're not "deferred" for synchronous operations (except insofar as they're not called immediately by you, but later on by the function you call).

The fact that the underlying system is event-driven is orthogonal to the use of deferred callbacks; you can imagine a (very slow) version of node.js that started a thread for every operation, and then called your given callback when the thread finished its work, without using events at all. Of course, this is a horrible model, but it illustrates my point :-)

0
9

The way a deferred callback works is each time you add a callback to it, that callback is pushed to an array. Then, when the .resolve() or .resolveWith() method is called on the deferred object, all .done() callbacks in the array are executed in order.

Now we can look at what a Deferred Object is. Take the snippet below as an example.

var deferred = $.Deferred();
var promise = deferred.promise();

What we have now is a deferred object, and the deferred object's promise object. The Deferred object has all the same methods as the promise object, however the promise object only has the methods .done(), .fail(), and .always() which are used to add callbacks to the deferred object for each respective event. The deferred object on the other hand has several other methods, most importantly .resolve() and .reject(). When these methods are called on the deferred object, all callbacks are called. .resolve() fires the .done() and .always() callbacks while the .reject() method calls .fail() and .always() callbacks.

Generally the deferred object is kept hidden within a private scope, and the promise object is returned from the function so that callbacks can be placed on it. The deferred object will be resolved later, such as after an ajax request is complete or after an image is loaded, after a setTimeout, etc. It is also important to realize that a deferred object can only be resolved once. If it is already resolved, it's callbacks will be called immediately.

Here's another example, one that I use:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

For more information on jQuery's $.Deferred() method and deferred objects, visit http://api.jquery.com/category/deferred-object/

1
  • This will probably be invaluable once I get my head round the concept of a deferred callback. Sorry, but I still don't understand the concept of what a deferred callback is. I am more looking for the conceptual idea behind it. Sort of along Mihia's idea. Once I can get my head round that then maybe I can understand js.
    – tentimes
    Apr 9, 2012 at 15:05
3

I am not sure but I believe a deffered callback refers to an asynchronous callback, so you'll have better luck googleing for that.

The best explanation I found was at http://www.nodebeginner.org

Hey, probablyExpensiveFunction(), please do your stuff, but I, the single Node.js thread, am not going to wait right here until you are finished, I will continue to execute the lines of code below you, so would you please take this callbackFunction() here and call it when you are finished doing your expensive stuff? Thanks!"

In this example, probablyExpensiveFunction is a non-blocking (or async function). This means that it's not executed right away, but placed in a so called event loop. The node.js thread will continue execution, but at some point in time, it will decide to execute something from the event loop. When it reaches probablyExpensiveFunction, it calls it, and when probablyExpensiveFunction finishes execution, it calls the (deferred) callback passed as as a parameter to it.

As an example of probablyExpensiveFunction you can take fs.readFile

8
  • Thanks. But, how is the expensive function going to do it's stuff if it has already returned and you are back in the main thread of execution? I don't get that bit. Are you saying the function persists in some way after it ends?
    – tentimes
    Apr 9, 2012 at 13:56
  • Edited the answer, maybe it's clearer now.
    – mihai
    Apr 9, 2012 at 14:14
  • Very helpful. But... do I have to process this array of stored callbacks? What I mean is, what is it that is processing this list. Is it (for example) that js lifts these callbacks in the background with you having to do nothing about it, or is it that a an event causes node.js or something to call a particular callback. Sorry, I am getting about 70% of what you are saying but am just a little lost on the rest :)
    – tentimes
    Apr 9, 2012 at 15:07
  • @tentimes - "what is it that is processing this list" the $.Deferred() object is processing the list. When you call .resolve() or .reject() on the original deferred object, the list of callbacks get called.
    – user400654
    Apr 9, 2012 at 15:19
  • 2
    @tentimes: From what you're saying, I'm not sure you completely grok the fact that functions in JS are first-class objects, and can therefore be stored until needed, past the time they are created. E.g. say you want to write to a file, then print out a log message; so you call the "write" function (or whatever) and pass it a function that outputs the log message. "write()" internally stores a reference to the given function, starts writing to the file, and sets up its own callback to know when the write is finished. It then returns before the write is done; when it is, your function is called.
    – Cameron
    Apr 9, 2012 at 15:23
3

JavaScript is single-threaded, so you can't think in terms of threads to understand this. Here is an example of both regular and asynchronous callbacks using jQuery:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);
3
  • Now this is getting me somewhere, thanks. So the asynchronous is in response to an event that I have setup with ajax - that just farms it out and if the event happens my callback gets called? I think I am getting it. Would node.js/jquery do something similar with jquery usnig deferred objects and a complicated system of interacting with them to really just do the same thing but using methods?
    – tentimes
    Apr 9, 2012 at 15:12
  • 1
    @tentimes, Exactly! Callbacks usually run in response to events (but since "callback" is not a js language construct, sometimes the term is used in other contexts). The deferred objects (promises) you see in Kevin's answer are basically syntactic sugar. They get "resolved" or "rejected" when some (asynchronous) event is triggered, then they call the appropriate callback ("done" or "fail", then "always"). Using them in jQuery can make the code more readable, and allows for some additional tricks (like easily adding a second callback after firing an ajax request, for example).
    – bfavaretto
    Apr 9, 2012 at 15:46
  • Both are asynchronous callbacks
    – Raynos
    Apr 9, 2012 at 18:39
1

Deferred callbacks (aka Promices) allow you to write sequential asynchronous code, without pain and callback spaghetti:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

'when' lets you wait for functions to return in parallel, and then can be sequentially chained.

one note: jQuery deferreds != Promices/A, their syntax is a bit different.

There are good articles on topic: one at IEBlog and other in some random blog, a book and a popular stackoverflow question

1
  • 1
    uhh.. it turns out - OP asked slightly different thing.. well, lets hope this answer will help someone else, someday, maybe.
    – c69
    Apr 9, 2012 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.