Let's clear some things up in what you said:
I am new(2 days!!) to the world of JavaScript and my only prior coding
experience is in Java where execution of statements takes place
sequentially. I understand that or at least I've read that JavaScript
is asynchronous which means that if there is a statement that takes a
long time to execute, the next statement is executed without holding
up the program for the first statement.
This is not how it works. A given function is either asynchronous or its synchronous by design. It has absolutely nothing to do with how long it takes to execute. You can have a very quick async function or a very long synchronous function. What determines whether the function is asynchronous or not is how it is designed. If it uses async I/O or timers or any other async infrastructure, then at least some of the execution of the function is asynchronous. That means that some of the function will finish LATER and some of the code right after this function call will execute BEFORE the async portion finishes.
I came across callbacks(a lot actually!!) but I couldn't see how they
could be used to determine the order of execution. I wrote a piece of
code just to understand how it could be done and I sure could use some
help.
Callbacks are used to notify the calling code when some asynchronous operation has completed. This can be used either to consume the result of the asynchronous operation or can be used to execute the next piece of code that wants to run in sequence after the async operation has finished.
In your code example, if you want the desired sequence, then you must call the callback inside the setTimeout()
callback so that it gets called AFTER the setTimeout()
called executes, thus giving you the desired sequence.
You also have to remove the callback
argument to the setTimeout
callback. That callback is not passed with that argument so declaring it there is just wrong. It can be accessed directly from the parent function via a closure as shown here:
console.log("Beginning");
function Test(callback){
setTimeout(function(){
console.log("Something that is asynchronous");
// call the callback here to indicate to the calling code
// that the asynchronous operation is now complete
callback();
},5000);
console.log("After Setting Timer");
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
This will generate a sequence in the console of:
Beginning
After Setting Timer
Something that is asynchronous
Should come last
Conceptually, the Javascript engine runs a single thread and that single thread uses an event queue. So, in your function above, this is what happens.
- The first
console.log("Beginning");
is executed.
Test(tstCallback)
is called.
- As part of executing the
Test()
function, a timer is scheduled. This registers a timer internal to the JS engine.
- The execution of code in
Test()
continues, console.log("After Setting Timer");
is executed and then that function finishes.
- The current thread of JS execution finishes and if there is nothing else in the event queue, then the JS engine has nothing to do, but wait for the next event to occur.
- Some time later (the 5 seconds that your timer is set for), the internal timer fires and it puts the timer event in the JS event queue.
- Since there is no other JS executing at the moment, the timer event is pulled out of the event queue and executed. This means that the original callback that was registered for the timer is called.
- As the timer callback is called, it executes the
console.log("Something that is asynchronous");
line and then calls callback()
.
- Your
tstCallback
function is then called and console.log("Should come last");
is executed.
- The async event finishes execution and the JS engine looks to see if there are any more events in the event queue. If so, the next event is pulled out of the queue and it is run.
There are a number of very good references on how Javascript handles asynchronous operations:
How does JavaScript handle AJAX responses in the background?
How Javascript Timers Work
Do I need to be concerned with race conditions with asynchronous Javascript?