Parker Malenke

Understanding the Javascript Event Loop

I’ve been working on a backbone.js website lately and one of the major paradigms of this framework is that events play an important role in driving the application logic (for example, a model is changed and subsequently emits an event informing a view of the need to update). To this end, all the major Backbone classes integrate a custom event system that allows objects to listen for events on other objects or to trigger their own events.

Event programming isn’t always the most intuitive, so I wanted to do a little research on how exactly events work in Javascript before sinking a bunch of time into the paradigm. This post collects my findings about events and the Javascript event loop, mainly for my own reference, but perhaps others will find it useful as well. Since I’m definitely not an expert on javascript, some of this may be incorrect—I will attempt to point out all areas where my understanding is fuzzy and provide code examples to illustrate my findings.

Say Hello to the Stack

Every time you call a function, the JS runtime (I believe this would be something like V8 in Chrome, Nitro in Safari, or whatever your browser implements) adds a frame to the stack. This is a last-in-first-out (LIFO) structure that manages all the functions you call. A frame consists of the arguments for the function, all its local variables, and the code contained in its block.

When you invoke a script the runtime will retrieve the first frame and start executing it. When it gets to another function call it pauses execution of the current frame, adds a frame for the internal function to the stack, and starts executing the new frame (the last in is the first out). Consider the example code in the figure below. The stack starts off empty because no functions have been called. When a is invoked a frame is created for it and added to the stack. In this example, the runtime will log a message to the console, and then come to the invocation of b. At this point it pauses execution of a, creates a frame for b, adds it to the stack, and begins executing b. Once b has completed the runtime will clear that frame off the stack and return to the frame for a. Once the last function completes the stack will be completely empty.

We can test this by adding some status messages to the code:

console.log('starting...');

function a() {
    console.log('added a to the stack');
    b('hello from b');
    console.log('removing a from the stack');
}

function b(msg) {
    console.log('added b to the stack');
    console.log(msg);
    console.log('removing b from the stack');
}

a();
console.log('...done')

This produce the following output:

[Log] starting... (index.html, line 9)
[Log] added a to the stack (index.html, line 12)
[Log] added b to the stack (index.html, line 18)
[Log] hello from b (index.html, line 19)
[Log] removing b from the stack (index.html, line 20)
[Log] removing a from the stack (index.html, line 14)
[Log] ...done (index.html, line 24)

It’s possible to put too many functions/frames on the stack at once (the infamous ‘stack overflow’); this can happen if you call a recursive function on an input that’s too large and spawns too many sub calls. Sounds like ES6 might be getting proper tail calls that would enable recursion over larger data sets.

Events

Alright, now back to the topic at hand. The first major point to realize is that there are two kinds of events in Javascript: synchronous and asynchronous. Most browser events are asynchronous, although a few are synchronous (such as DOM mutation and Nested Dom events). Any custom event handling, such as the events module built into backbone.js, another custom solution like EventEmitter, or jQuery’s .trigger() function, is going to be a synchronous implementation. So what’s the difference between these types of events?

Synchronous Events

Synchronous events are basically another way of invoking functions. Emission of these events essentially involves walking through a list of listener/handler functions and calling them. Consider the following sample implementation:

var EventManager = (function() {
    var _events = {}; // private storage for events and their listeners

    return {
        // if the event already exists, add the callback
        // otherwise create it with the given callback
        on: function(event, callback) {
            if (_events[event]) {
                _events[event].push(callback);
            } else {
                _events[event] = [callback];
            }
        },

        // invoke all the functions registered with an event
        trigger: function(event) {
            var ev = _events[event] || [];

            for (var i = 0; i < ev.length; i++) {
                ev[i].call();
            }
        }
    };
})();

So synchronous event systems are really just a way to invoke one or more functions without knowing what those functions are at the point when the event is triggered. Calling EventManager.trigger() pauses execution of whatever block you’re in and then sequentially invokes each of the listeners, adding and removing them from the stack until the list is exhausted, at which point control is returned to the context that emitted the event.

Consider this example:

// Make a plan for a martian landing
function tellThePublic() {
    console.log('The martians are coming!');
}
EventManager.on('martians:landed', tellThePublic);

function react() {
    console.log('Head for the hills!');
}
EventManager.on('martians:landed', react);

console.log('Our plan is now in place');


// later...
EventManager.trigger('martians:landed');
console.log('Plan executed');

This will output:

[Log] Our plan is now in place
[Log] The martians are coming!
[Log] Head for the hills!
[Log] Plan executed

Notice that when the event was triggered, execution of the main script was paused while all the listeners were invoked (i.e. ‘Plan executed’ wasn’t logged until the plan was actually carried out). In this case execution followed these steps:

  1. Triggering the 'martians:landed' event pauses the main context
  2. tellThePublic() is added to the stack
  3. tellThePublic() is pulled off and executed
  4. react() is added to the stack
  5. react() is pulled off and executed
  6. Main context resumes and 'Plan executed' is logged

Asynchronous Events

Instead of acting as a shortcut for adding frames to the stack, triggering async events adds messages to a queue. This behavior can’t be simulated with third party code (at least not that I’m aware of). Before discussing the queue, what kind of events are asynchronous? In my research it sounds like pretty much any event that comes from the browser, or in node any event that comes from a built in object. Clicks on elements, window.setTimeout callbacks, mouseovers, keypresses, XMLHttpResponse’s readyState, etc. all behave in an asynchronous fashion.

The Event Queue

In addition to the stack, javascript runtimes include a structure known as the queue. This is similar, except that it operates on a first-in-first-out (FIFO) basis. Whenever you register an event handler for an async event the runtime makes a note associating the provided function with the specified event. When an event is triggered the runtime looks through its list of handlers to see if any are associated with the current event. If so, it creates a message, which references the handler function, and adds it to the queue. How are messages from the queue invoked? That’s the job of the event loop.

The Event Loop

Whenever the stack is empty, the runtime will ask the event loop for the next available message. If one exists, the event loop hands the associated function off to the runtime, which creates a corresponding frame, adds it to the stack, and executes it. Note the major difference versus synchronous events here: Async event handlers are only ever invoked when the stack is empty.

Here is a figure illustrating the sequence of events (zing!) that happens when dealing with an async event:

Code Example

Okay, let’s look at some code. Here’s an example that will hopefully make this clearer.

// create a handler function and add it to the click event
function broadcast() {
    console.log('A click event was fired!');
}
document.addEventListener('click', broadcast);

If you were to run this example and start clicking around you’d see the message would be logged to the console pretty much in real time as you click the document. Note that in this case the stack is basically empty this whole time. Now let’s try it with a stack that has more stuff to do.

// here's a long running function
function runFor(ms) {
    ms += new Date().getTime();
    while (new Date() < ms){}
    // yes this is very hacky
}

// now run this on the stack while we're listening for the click event
function broadcast() {
  console.log('A click event was fired!');
}
document.addEventListener('click', broadcast);

runFor(5000);

Now if you run this and start clicking on the document you’ll see that nothing is logged for 5 seconds and then all of a sudden a bunch of strings are logged. This is because the runFor() function stays on the stack for 5 seconds. No messages from the event queue can be handled until the stack is clear. Once it finally clears all the messages are handled in sequential order. To check that messages are handled in a FIFO manner try the example with a different handler:

var broadcastCounter = (function() {
    var _count = 1;
    return function() {
        console.log('Click number: ' + _count);
        _count++;
    }
})();
document.addEventListener('click', broadcastCounter);

You should see that the strings are printed in sequential order starting at 1 and going up.

Remaining Questions

At this point I feel like I have a pretty good handle on the event loop and asynchronous events. There are still a few points that aren’t entirely clear, but I have some guesses at what the answers are.

Is a call to addEventListener() blocking?
Functions that register async event handlers tend to return pretty much instantaneously. My guess is that in a strictly single threaded environment these functions will block the execution of a script until the runtime finishes recording the event and respective handler (step 2 in the diagram). I suppose it’s possible that some of the runtime maintenance tasks like this could also occur in a separate thread/process.

Is the message enqueueing process blocking?
When an async event is triggered, does the runtime pause execution of the script while it looks up the relevant handler and adds it to the event queue? Again, I think this would work as a concurrent process, but it’s not required.

Do async processes ever occur simultaneously?
The examples I had in mind were file reads in node.js or ajax requests in the client. I’m pretty sure ajax requests can occur concurrently, with something along the lines of:

  1. You create an XMLHttpRequest object, this blocks the main thread while telling the browser where to get the resource, what headers to use, etc.
  2. Once the browser gets all this info, your function returns and execution continues.
  3. While your execution is continuing the browser has started a request in another thread. Your continuing execution might start additional ajax requests, which might also occur concurrently if the browser supports multiple http requests (I think they all do these days).
  4. When that request returns an event is fired and your callback is added to the event queue.
  5. The stack empties at some point and your callback is taken off the event loop and executed with the results of the request.

I’m not sure about file reads in node.js. My guess is that it’s a similar process, except that a file read kicks off a separate thread at the OS level that then returns with the results of the file. In this manner you could have your js executing in one thread, a file read executing in another thread, and an ajax request executing in a third thread. So you can have concurrent execution with javascript, it’s just that only one script is ever executing at a time (the other threads are in the browser or at the OS level).

Conclusion

So that’s my brief foray into javascript events and the event loop. For functions that don’t take too long to execute it probably doesn’t matter if you’re using synchronous or asynchronous events, but if you have anything that could hold up the main thread for very long or are attaching an event handler that could take a while to clear it’s good to know the differences.

Takeaways

Resources

Examples

A New Year and a New Book Rating Scheme

A few days ago I completed my goal of reading 35 books in 2013. I’ve logged all the books I’ve read for the past three years now (on Goodreads), and it’s kind of nice to look back at my recent literary history with ease. When I started rating books I didn’t really have much of a plan for which books got which ratings. And I felt bad about giving books negative ratings, meaning I rarely gave out one or two stars. This paradigm doesn’t have much expressive power, so starting with books I read in 2014 I’m going to use a new rating scheme, specified here:

★★★★★
I absolutely loved the book—wouldn’t change anything about it. There’s a good chance I’ll recommend these books to most people.

★★★★
A very good book. Stood out as an above average read that I enjoyed a lot. Still, some aspects of the book could use improving before reaching five star status.

★★★
Solidly average. No real negatives, but nothing truly outstanding either. Worth spending the time to read, but not necessarily worth re-reading.

★★
Below average. Some redeeming qualities, but my time would probably have been better spent elsewhere. Might still recommend to others if I felt they could enjoy it more.


A bad book. Didn’t enjoy it, and didn’t really find anything beneficial in it. Wouldn’t recommend to others.

My new rubric doesn’t necessarily depend on the re-readability of a book. There are some fantastic books that I would never really plan on re-reading, either because the style of the book doesn’t lend itself to that or just because of logistics. (How many times can one read Infinite Jest?)

Gene Patents and the Supreme Court

The US Supreme Court recently issued a ruling in the case Association of Molecular Pathology v. Myriad Genetics that addresses the validity of patents on genes, including those on portions of the human genome. This decision determined that naturally occurring genes are products of nature and therefore ineligible for patent protection, but confirmed that cDNA (complementary DNA) can be patented. It’s fantastic to see the legal system recognize genes as the natural resources that they are, although the decision should have extended to cDNA as well.

Typical genes in eukaryotic cells (those that make up complex multicellular organisms like humans) contain two types of sequences termed introns and exons. In the process of expressing a gene the intron sections are cut out and the exon components are spliced together producing the final sequence that gets turned into the end product, a protein. The cDNA version of a gene is the same as the version found in a chromosome, just with all the introns removed. So why can corporations patent cDNA and not the regular DNA found in end genome?

The catch is that cDNA isn’t technically a naturally occurring product. In the cell, the processed version of the full gene is actually made out of RNA, a molecule similar to DNA but different in a few key ways. Researchers often make cDNA from isolated RNA, however, using very simple and common procedures because the processed version of a gene is much easier to work with for many standard laboratory experiments.

At the start of the genomics era it was difficult and expensive to decipher what the sequence for a given gene was, but in the years since the turn of the century the cost has decreased dramatically, even outpacing Moore’s law over the past few years. The general idea behind patents is to provide an incentive for members of society to undertake an initial outlay in costs that will eventually produce something beneficial to society. What the Supreme Court is communicating with their ruling is that the production of cDNA for certain genes is an activity beneficial to society but which requires a monetary incentive for researchers to undertake that task. This is simply not the case however. The identification of a naturally occurring gene sequence is very easy and inexpensive with modern procedures, and producing a cDNA version of a gene is even easier. Our constitution specifies that patents are to be granted “to promote the progress of science and useful arts”, yet it’s not clear why the court believes cDNA patents are necessary for accomplishing this goal.

The ruling itself contains language that could potentially invalidate cDNA patents. In their opinion the justices “hold that genes and the information they encode are not patent eligible…simply because they have been isolated from the surrounding genetic material.” The process of producing cDNA is arguably a method of isolating the information encoded by a gene from surrounding genetic material.

Ultimately, the invalidation of patents on DNA sequences found in the genome is more important than the lifting of intellectual property restrictions on cDNA. The ruling allows genetic screening of the genome (tests which can identify gene variants to help doctors make treatment decisions) without interference from patent holders like Myriad Genetics, who until now could charge licensing fees or prevent companies and researchers from conducting the tests at all. This is an important step forward for the sciences, and it’s encouraging to see that this was a unanimous decision amongst the justices. cDNA patents could potentially prove troublesome to researchers investigating patented genes, but perhaps those restrictions will be removed in time as well.

How To Teach College Students

This guide contains my thoughts as a seasoned college student on what makes a teacher good or bad. Nearly forty instructors over three years of college level education have constructed this understanding of educators. Some taught me how to deal with bureaucracy, some taught me how to transcribe slide shows onto lined paper, some taught me a little, some taught me a lot. In my experience, a number of good or bad practices exist which combine to determine the overall quality of a teacher. Hopefully this manifesto of sorts will drive beneficial change in the typical college classroom experience. Of course, the advice proffered below predominantly reflects my perception of education and does not represent an exhaustive collection of student opinions. I do believe, however, that many students would benefit if teachers put these principles into broader practice. At least my ideas might provoke discussion among teachers and students about efficient transmittance of knowledge.

Good Ideas

Transparency

Teachers must understand what we as students need to know and then clearly communicate it to us. This applies to the general course material in addition to individual homework assignments and exams. I find it frustrating, if not disrespectful, when teachers fail to clearly delineate what they expect of students. My best experiences with such clarity have come from math classes that were typically organized with a very manageable load of weekly homework, which applied concepts from well articulated lectures, and periodic exams that students entered possessing well-formed notions about the types of problems to expect. Here are the key points:

Organization

Transparency goes cheek by jowl with organization. A minimal and consistent class structure helps significantly when establishing an accessibly organized (and hence transparent) class structure.

Typography

This is a little pet peeve of mine and perhaps less important to creating a good learning experience, but still influential. Good typography competes with good grammar when creating clear and professional communication. You can find several good resources for learning more about this essential subject online. (Here, here, here, and here).

Bad Ideas

Independent Floundering

I believe every student should exhibit proficiency at independent learning. It forms an essential part of being a genuine individual. With that said, I am paying you through the nose to facilitate my learning. I expect you to teach me. All too often, however, a teacher’s attempt at encouraging students to learn a topic outside of class results in the pupil simply floundering around online, bouncing back and forth between Yahoo Answers and Wikipedia.

Entertaining

Do not set out to entertain us. College students know an infinitude of ways to keep themselves better entertained than attending class. Your attempts will simply muddle up the concepts and add to the effort students expend on extracting information from class. Focus on teaching your material in a clear, concise, and accessible manner. If some students find themselves enjoying class, so much the better.

Severity

A college education is rooted on the idea of a contract between the school (professors) and students. We have mutually agreed that the school will provide knowledge and the students will provide money. Besides the simple standards of professionalism and etiquette applicable in any social situation, this is the extent of any obligation students have to professors. Specifically, professors should not impose penalties on behavior they personally and individually disapprove of but which does not impede other students. For example, skipping class, unobtrusively texting, working on the crossword, completing homework from other classes, etc. Of course all these activities may be viewed negatively, but the professor still receives payment, the contract is upheld. Once such activities impinge on the ability of other students to receive instruction action may be undertaken. But setting strict, arcane rules at the outset serves more to create a degree of hostility between students and the teacher.

Repetition

Some students may need to hear a concept several times in several contexts before comprehending it. Some may simply need a brief reminder of it. Do not treat these two the same.

Online Anything

Digitization of homework or quizzes has never aided students and only added a depressingly high administrative and logistical barrier between their brains and course material.

Gran Torino Review

I nearly always have certain expectations when I go to see a movie. Rarely does the movie fit those preconceptions. Sometimes it falls short, sometimes it surpasses. Only once in a great while does a film deliver so far beyond my hopes as Gran Torino did.

A very complex, but never confusing tale, Clint Eastwood’s performance contains meaningful conversation on manhood, family, race, neighbors, courage, conviction, life, and death. With excellent acting and a beautiful production quality, this film should be on everyone’s list.

← Previous Page 1 of 2 Next →