A Program in Chunks

You may write your JS program in one .js file, but your program is almost certainly comprised of several chunks, only one of which is going to execute now, and the rest of which will execute later. The most common unit of chunk is the function.

The problem most developers new to JS seem to have is that later doesn’t happen strictly and immediately after now. In other words, tasks that cannot complete now are, by definition, going to complete asynchronously, and thus we will not have blocking behavior as you might intuitively expect or want.

Consider:

  1. // ajax(..) is some arbitrary Ajax function given by a library
  2. var data = ajax( "http://some.url.1" );
  3. console.log( data );
  4. // Oops! `data` generally won't have the Ajax results

You’re probably aware that standard Ajax requests don’t complete synchronously, which means the ajax(..) function does not yet have any value to return back to be assigned to data variable. If ajax(..) could block until the response came back, then the data = .. assignment would work fine.

But that’s not how we do Ajax. We make an asynchronous Ajax request now, and we won’t get the results back until later.

The simplest (but definitely not only, or necessarily even best!) way of “waiting” from now until later is to use a function, commonly called a callback function:

  1. // ajax(..) is some arbitrary Ajax function given by a library
  2. ajax( "http://some.url.1", function myCallbackFunction(data){
  3. console.log( data ); // Yay, I gots me some `data`!
  4. } );

Warning: You may have heard that it’s possible to make synchronous Ajax requests. While that’s technically true, you should never, ever do it, under any circumstances, because it locks the browser UI (buttons, menus, scrolling, etc.) and prevents any user interaction whatsoever. This is a terrible idea, and should always be avoided.

Before you protest in disagreement, no, your desire to avoid the mess of callbacks is not justification for blocking, synchronous Ajax.

For example, consider this code:

  1. function now() {
  2. return 21;
  3. }
  4. function later() {
  5. answer = answer * 2;
  6. console.log( "Meaning of life:", answer );
  7. }
  8. var answer = now();
  9. setTimeout( later, 1000 ); // Meaning of life: 42

There are two chunks to this program: the stuff that will run now, and the stuff that will run later. It should be fairly obvious what those two chunks are, but let’s be super explicit:

Now:

  1. function now() {
  2. return 21;
  3. }
  4. function later() { .. }
  5. var answer = now();
  6. setTimeout( later, 1000 );

Later:

  1. answer = answer * 2;
  2. console.log( "Meaning of life:", answer );

The now chunk runs right away, as soon as you execute your program. But setTimeout(..) also sets up an event (a timeout) to happen later, so the contents of the later() function will be executed at a later time (1,000 milliseconds from now).

Any time you wrap a portion of code into a function and specify that it should be executed in response to some event (timer, mouse click, Ajax response, etc.), you are creating a later chunk of your code, and thus introducing asynchrony to your program.

Async Console

There is no specification or set of requirements around how the console.* methods work — they are not officially part of JavaScript, but are instead added to JS by the hosting environment (see the Types & Grammar title of this book series).

So, different browsers and JS environments do as they please, which can sometimes lead to confusing behavior.

In particular, there are some browsers and some conditions that console.log(..) does not actually immediately output what it’s given. The main reason this may happen is because I/O is a very slow and blocking part of many programs (not just JS). So, it may perform better (from the page/UI perspective) for a browser to handle console I/O asynchronously in the background, without you perhaps even knowing that occurred.

A not terribly common, but possible, scenario where this could be observable (not from code itself but from the outside):

  1. var a = {
  2. index: 1
  3. };
  4. // later
  5. console.log( a ); // ??
  6. // even later
  7. a.index++;

We’d normally expect to see the a object be snapshotted at the exact moment of the console.log(..) statement, printing something like { index: 1 }, such that in the next statement when a.index++ happens, it’s modifying something different than, or just strictly after, the output of a.

Most of the time, the preceding code will probably produce an object representation in your developer tools’ console that’s what you’d expect. But it’s possible this same code could run in a situation where the browser felt it needed to defer the console I/O to the background, in which case it’s possible that by the time the object is represented in the browser console, the a.index++ has already happened, and it shows { index: 2 }.

It’s a moving target under what conditions exactly console I/O will be deferred, or even whether it will be observable. Just be aware of this possible asynchronicity in I/O in case you ever run into issues in debugging where objects have been modified after a console.log(..) statement and yet you see the unexpected modifications show up.

Note: If you run into this rare scenario, the best option is to use breakpoints in your JS debugger instead of relying on console output. The next best option would be to force a “snapshot” of the object in question by serializing it to a string, like with JSON.stringify(..).