0

I'm having a bit of trouble understanding the mechanics of JS callbacks. I have a fair idea of how callbacks can be used in JS, but I do not understand how a callback is asynchronous.

For e.g., if my understanding is correct, a callback is of the nature:

db.query(param1, param2 , callback_fn1(){..} );

And the implementation of db.query() is along the lines of :

 db.prototype.query = function(p1 , p2 , callback ){
      //some code 
      callback();
}

How does the above implementation make db.query an asynchronous function? Does this not mean that a function called callback is passed to query and that function is called inside query? It looks like query is just another synchronous function. Could someone help me understand what I'm overlooking here? Thanks!

6
  • You are right about this being blocking code. For non-blocking code you need to use something like setTimeout, rely on built-in asynchronous methods (i.e. HTML5 FileReader API), ajax requests, web workers or DOM events. Commented Sep 29, 2013 at 16:29
  • @IngoBürk : Could you write a detailed reply demonstrating what you mean? Maybe as an answer? Commented Sep 29, 2013 at 16:32
  • Done. Seeing the second answer I'm gonna point out that I'm talking about browser-javascript. Node.js has other options (see the other answer). /edit: Just now noticed you tagged your question with nodejs. Commented Sep 29, 2013 at 16:50
  • Once you get your head wrapped around callbacks, you may also want to take a look at promises. Once you start chaining async functions in callbacks you end up with pyramid code or callback soup. Commented Sep 29, 2013 at 16:58
  • @IngoBürk : The example in the question relates to db.query, I'm believe that itself is a fair indication of it being back end code ;). Commented Sep 29, 2013 at 17:10

2 Answers 2

3

The code sample you've shown is actually still synchronous because is instructed to run immediately. An asynchronous callback is a callback that doesn't immediately need to be executed, so it doesn't block the event loop until you instruct it to run.

The most common way in Node.js to do this is with process.nextTick() which runs a specified function when the event loop call stack is empty. Here's an example:

var async = function(args, callback) {
  // do some work
  process.nextTick(function() {
    callback(val);
  });
};

Then we call the function like this:

async(args, function(val) {
  console.log(val);
});
console.log('end');

In this example, the function async() and console.log('end') are added to the call stack. The call stack empties once both of those functions are run, and once it's empty, console.log(val) then runs.

If you're still confused, think of process.nextTick() as an optimized version of this code:

var fn = function() {};
setTimeout(fn, 0);

It basically means "run this function as soon as possible when you are not busy".

Sign up to request clarification or add additional context in comments.

6 Comments

Just to clarify this: Your solution is the node.js solution
I will make note in the post, as I was unsure which the person who asked was asking about.
I just now realized that the question is actually tagged with nodejs – my fault.
@hexacyanide great answer! Very succinct.
A good cross-platform alternative to process.nextTick is setTimeout(...,0) which never executes immediately (even with timeout of zero), is always asynchronous, executes in the next round of the event loop and thus on node.js behaves exactly equivalent to process.nextTick
|
2

Edit: I just now realized the question is tagged with node.js. My answer is more about Javascript in the browser, @hexacyanide's answer is more about node.js. I guess knowing both doesn't hurt, though!

The way you posted it the code will indeed be blocking. For asynchronous behavior there are a few things you can utilize, such as

  • setTimeout and setInterval
  • Built-in, asynchronous methods such as from the FileReader API
  • Ajax requests
  • Web workers (see @html5rocks)

Your example code could be written as follows (fiddle):

function doStuff(callback) {
    setTimeout(function () {
        for (var i = 0; i < 1000; i++) {
            // do some busy work
            var x = Math.sqrt(i);
        }

        callback();
    }, 0);
}

console.log('start');
doStuff(function () {
    console.log('callback called');
});
console.log('after doStuff()');

The setTimeout call will allow the Javascript interpreter/compiler (however exactly they work these days) to run the function in a non-blocking matter which is why (most likely), you will see the output

start
after doStuff()
callback called

Note that asynchronousity is different from multi-threading. Javascript is still single-threaded (with the exception of web workers!).

A more in-depth explanation can be found for example here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.