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?
WebWorkers aside, the JavaScript programming model in the browser is purely single-threaded. You can make your call somewhat asynchronous by using window.setTimeout:
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 thereforedoSomething(myCallBack)will not be invoked) until yourmain()function finishes, assuming that is the end of your JavaScript.One unfortunate consequence of this
setTimeout-based approach is thatdoSomething(myCallBack)doesn’t get invoked in parallel alongsideconsole.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.