views:

101

answers:

4

This example is JavaScript, since that's where I'm using callbacks mostly. I want to understand how they work at a low level.

In the example below, I'd expect everything to happen in order and "calling back" to occur after "step 3" and before "step 4." This makes sense to me, as everything is done in order on a single thread of execution. There's no trickery. The only thing that is sort of special is that you've passed a function to another function.

function main() {
  console.log("step 1");
  console.log("step 2");
  doSomething(myCallBack);
  console.log("step 4");
}

function doSomething(f) {
  accessTheDatabase(); // this could take a while
  console.log("step 3");
  f(); // done - now call back
}

function myCallBack() {
  console.log("calling back!");
}

How would you make doSomething asynchronous so that "step 4" can be executed before, or in parallel with, "step 3"?

I assume that if doSomething were somehow called asynchronously, it would have to be on a diffferent thread, no? And if so, when it finishes and then calls myCallBack, does the callback happen on the second thread or on the main thread? If it happens on the main thread, why does the second thread even need a pointer to the callback function? How does the inter-thread call work?

A: 

You would need multiple threads of execution to do this, which I do not believe you can do in Javascript (although correct me if I'm wrong). However if you were writing a C/C++ program, look at the pthreads package (or libdispatch on Mac OS X 10.6).

Edit: a Google search for "threads javascript" turns up some possibly interesting results.

SiliconValleyer
A: 

Using callbacks the way you are (function declaration name or function expression variable name as an argument to another function), they are synchronous. To make them asynchronous, you can wrap them in a setTimeout.

eyelidlessness
-1: wrong (filler)
trinithis
@trinithis, how am I wrong?
eyelidlessness
+4  A: 

WebWorkers aside, the JavaScript programming model in the browser is purely single-threaded. You can make your call somewhat asynchronous by using window.setTimeout:

window.setTimeout(doSomething, 0, myCallBack);

This effectively places the call doSomething(myCallBack) onto the timer queue, and after 0 or more milliseconds elapse, it will eventually get invoked. However, as with all asynchronous calls in JavaScript, you must relinquish the execution context before any asynchronous callbacks can be invoked; that is, the timer queue will not be processed (and therefore doSomething(myCallBack) will not be invoked) until your main() function finishes, assuming that is the end of your JavaScript.

One unfortunate consequence of this setTimeout-based approach is that doSomething(myCallBack) doesn't get invoked in parallel alongside console.log("step 4"). On the other hand, consider XMLHttpRequest.send; after making this call, the rest of your JS can continue to execute while the browser issues the HTTP request. Your script does need to finish executing before the onreadystatechange handler can execute, but most of the HTTP connection work can happen in parallel while JS executes.

ide
In the `XMLHttpRequest.send` case, I assume that happens on another thread. When it's done and the `onreadystatechange` handler executes, which thread does that happen on?
vg1890
This happens on the main JavaScript thread. Implementation-wise, this can be any thread, but conceptually JavaScript (and the DOM, for that matter) executes within a single thread.
ide
I guess the confusing part is that it's called a "callback." That, to me, says "here's a function, please call this when you're done doing your thing. I'll be off doing my own thing." When really, the browser finishes the AJAX call and then interrupts the main thread (via what mechanism??) and the main thread itself calls the function that it registered as the callback. Am I right?
vg1890
Conceptually, there are no interrupts. For a moment, pretend that the world has no concurrency at all—you ask the browser to make an AJAX call or to react to mouse clicks, but it cannot do anything until your JS finishes. Only after this point can the browser decide to notify you that the server responded to your AJAX call or the user clicked the page; the JS interpreter starts up once more and runs your callback. (This isn't too far-fetched—the browser cannot process click events, etc. while your JS runs.)
ide
+2  A: 

Hmmm.. something looks wrong (I have done v little JavaScript): you pass myCallBack to the function doSomething() but you dont call it back!? You would have to have a call to f() inside doSomething() or pass it to another function which will call it back once your long operation is complete.. And no callbacks are not inherently asynchronous - in your case you are running it all on the same thread (even if accessTheDatabase() is asynchronous in which case it would immediately return!) - so it will still go Step1, Step2, Step3, Step4. I beleive you want:

function main() {
  console.log("step 1");
  console.log("step 2");
  doSomething(myCallBack);
  console.log("step 4");
}

function doSomething(f) {
  accessTheDatabase(f); // assuming this is an asynchronous operation and calls the callback f once done
}

function myCallBack() {
   console.log("step 3");
}

In answer to the second part of your question: the callback would be run on which ever thread you are calling it from - to run a callback on another thread you would have to join() that thread first then invoke() or begininvoke() the callback - though there may already be some built in way to dispatch your callback onto a queue of things to be run on the thread you want to run it on (often the case with UI threads) NOTE: It may already be that accessTheDatabase() does run the callback on the thread that called it - using one of the afore mentioned methods...

Mrk Mnl
You're right! Thanks for the catch.
vg1890
My pleasure, mark it as the answer if it is :)
Mrk Mnl
updated answer for the 2nd part of your question - which thread it is run on
Mrk Mnl