Asynchronous JavaScript: The Event Loop

Today I attended Will Sentance’s workshop “JavaScript Hard Parts” on Frontend Masters. It was a foundational overview of how asynchronous JavaScript is processed using the JavaScript Event Loop. This is not a perspective that I have studied before. Perhaps I should have. Learning about it helped me to understand how things work at a deeper level across the entire language.

The first building block to understanding asynchronous JavaScript is to identify the core processing components of JavaScript, and understand how they work together using the Event Loop. Below is a brief walk through it.

JavaScript Processing Components

  1. JavaScript Engine
  2. Runtime Environment (usually a web browser or Node.js)
  3. Event Queue
  4. Call Stack

The JavaScript Engine is the component that compiles and executes JavaScript. This may seem obvious, but consider a call to setTimeout. That is not a JavaScript function. setTimeout is an Environment API method. All methods that interact with the DOM are also Environment APIs.

Pure JavaScript, ie: var num = 10;, is processed in the JavaScript Engine. But Environment API methods are processed outside of the JavaScript Engine in the Runtime Environment. If it weren’t for these Environment APIs, JavaScript would be far less useful because it would not be able to interact with the outside world. So, it’s important to understand how the components work together using the JavaScript Event Loop. Let’s look at a simple example.

JavaScript Event Loop

function sayHi() {
    console.log('hi');
}

setTimeout(sayHi, 0);

console.log('hi first');

On line 1, sayHi is declared as a function in the global scope. Memory is allocated in the JavaScript Engine, and the body of the function is stored (lines 1–3). sayHi points to that location in memory. You can verify this in your browser’s console.

Want a better understanding of how declaration, assignment, and execution is processed in JavaScript? Check out my post on Hoisting in JavaScript.

Screenshot of a value referencing a function in Chrome Dev Tools
Function Reference In Memory

On line 5, setTimeout is called. This is where things get interesting. Because setTimeout is an Environment API, it is processed outside of the JavaScript Engine in the Runtime Environment. As you may know, the second parameter of setTimeout accepts a number argument representing a delay. While you could say this delay defines how long it should be until sayHi is executed, more specifically, it defines how long it will be until sayHi is added to the Event Queue by the Runtime Environment.

In our example, sayHi will be added to the Event Queue after 0 milliseconds. It will remain in the Event Queue until the Call Stack is completely empty. The Call Stack will be empty when all functions in all scopes have executed. At that point, the Event Queue will push the first item its queue (sayHi) to the top of the Call Stack. The process of monitoring the Call Stack, then transferring items from the Event Queue to the Call Stack is referred to as the “Event Loop“.

The Event Loop operates on a first-in, first-out order (FIFO for you accountants turned programmers). A mental model of this process can be established with the analogy of taking trip to the store. You leave your home (the JavaScript Engine) for the store (the Runtime Environment). There, you put an item in your shopping cart and head to the checkout line (the Event Queue). Once it is your turn, you move the item from your cart to the top of the checkout counter (the Call Stack) and the transaction is processed. You then head back to your home (the JavaScript Engine) with the item.

Meanwhile, just because you left to run an errand doesn’t mean the activity at your house stops. So, to complete the analogy, while setTimeout is processed in the Runtime Environment, then added to the Event Queue, before being pushed to the Call Stack, console.log('hi first'); is executed. That is why you see hi first logged before hi.

Screenshot containing an asynchronous function execution to illustrate the JavaScript Event Loop
Asynchronous Function Execution

I hope this explanation helps to clarify how the JavaScript Event Loop works. Thanks for taking the walk!

Asynchronous JavaScript: Promises

What is a Promise?

A promise is a placeholder for the result of an asynchronous operation. That’s it. JavaScript Promises may seem like a very complicated concept, but they are not. A promise is just placeholder.

Why do Promises Exist?

Promises make flow-control easy to manage. The more complex an application gets, the more difficult flow control becomes. Before promises, event-driven patterns like pub/sub were popularized. They have their place and will remain popular. But event driven architecture is reliant upon event handlers being bound prior to an event occurring. If for instance a button were clicked before a click handler was bound, nothing would happen. This is a problem that promises solve.

But before you think that you should change everything to a promise, wait. You should not. Event driven architecture is extremely helpful for simple user interaction. Where event driven architecture becomes problematic is complex systems/network interaction.

When Node.js was created, it solved this problem with the callback pattern. In the callback pattern you don’t have to worry about event handlers being registered before an event is triggered because the handlers are passed as arguments – callback arguments. The callback pattern makes chaining multiple [callback] functions throughout the flow of a program simple. But that simplicity can quickly become a nightmare – just Google “callback hell” for the pitfalls of the callback pattern.

So back to the question, why do promises exist? JavaScript needed a better way to manage flow control. Ahhhhh, we’ve come full circle.

What Happens in a Promise?

First, let’s remember what a promise is: a promise is a placeholder. When a promise is explicitly assigned via the Promise() constructor, or implicitly returned from a method like fetch(), what is actually returned from either scenario is just an object. The returned object’s __proto__ property points to Promise. So, we call it a “Promise Object”. But do remember that it’s just an object. If you look through the prototype chain shown in the screenshot below, you’ll see just one level up that the __proto__ property points to Object.

Basic JavaScript Promise
Basic JavaScript Promise

Okay, moving on. The promise object that is returned contains an internal [[PromiseStatus]] property. There are three status values that this property can have, which together comprise the “Promise Life Cycle”. Those statuses are:

  • "pending": this is the first status. It indicates the underlying operation has not completed. A promise will always have a pending status at some point in its life cycle.

  • "fulfilled": this status indicates that the underlying operation has successfully completed.

  • "rejected": this status indicates that the underlying operation did not complete. This may be due to a bug, network issue, etc.

Again, those are the statuses that comprise the life cycle of a promise in JavaScript.

Let’s talk about the state of a promise. State in promises is very simple, it’s either settled or unsettled. When a promise’s status is "pending", its state is unsettled. When a promise’s status is "fulfilled" or "rejected", its state is settled. Simple when it’s not over complicated, huh?

Let’s Review Promises

  • A promise is a placeholder for the result of an asynchronous operation.
  • Promises make flow-control easy to manage.
  • Promises have three statuses that comprise their life cycle: pending, fulfilled, and rejected.
  • Promises have two states: settled and unsettled.

Final Word on Promises

I’ve seen/read/viewed a lot of people who use the terms “status” and “state” loosely – even interchangeably at times. This causes a lot of confusion.

Understanding the difference between “status”, “state”, and “life cycle” is critical to understanding promises. Conflating these terms is one of the main reasons promises seem so confusing. Understand them, and you are well positioned to mastering promises.

Google Analytics Custom Events Emitter

A while back I looked in to implementing Google Tag manager so that marketing folks at my company could manage custom events in Google Analytics. Beyond custom events, I’m not sure what Google Tag Manager does (it’s been a while since I looked at it). Perhaps there are a bunch of great benefits that I am missing.

I ended up not deploying Tag Manager for the same reason that others would choose to deploy it: simplicity. For me, the best way to keep things simple is to avoid another application abstraction and just use code. So, I created a JavaScript module that allows me to easily add custom events. Below is the code for my Google Analytics custom events emitter module.

// ----------------------------------------------------
// ---------- GOOGLE ANALYTICS CUSTOM EVENTS ----------
// ----------------------------------------------------
/*
    Assign an `analyticsEvents` property to a global `APP` object. This property
    stores our module. The immediately invoked function expression (IIFE)
    assigned to this module ensures that all code within the module is contained
    within its own scope (the module scope). jQuery is passed as an argument
    which is assigned to the `$` character. This way, we protect jQuery from
    conflicting with other libraries that also alias to the $ character.
 */
APP.analyticsEvents = (function($) {

    /*
        Assign Google Analytics "Event Actions" to constants. This prevents us
        from passing the wrong event action to Google. In the case of a typo, we
        get an "undefined" error instead of not seeing an error at all.
     */
    var APPLY = 'Apply',
        BROWSE = 'Browse',
        CLICK = 'Click',
        LOGIN = 'Login',
        REGISTER = 'Register',
        REQUEST = 'Request',
        SEARCH = 'Search',
        SUBMIT = 'Submit',
        SUBSCRIBE = 'Subscribe';

    /*
        All of our custom events are stored in an `events` object. Each key in
        the `events` object corresponds to a Google Analytics "Event Category".
     */
    var events = {
        /*
            An array is assigned to each key in the `events` object. Each index
            of the array contains sub arrays. The sub arrays contain the actual
            events.

            The first index of the sub array is a `data-event` attribute that we
            add element(s) in the DOM. The Second index of the sub array is the
            Google Analytics "Event Action" (where our constants created above
            are used). The third and final index of the sub array is the Google
            Analytics "Event Label".
         */
        'Account Actions': [
            ['[data-event="start-account-create"]', REGISTER, 'Start Account Registration Before Checkout'],
            ['[data-event="start-account-create-quote-checkout"]', REGISTER, 'Start Account Registration During Quote Checkout'],
            ['[data-event="create-account"]', REGISTER, 'Register Account Before Checkout'],
            ['[data-event="create-account-order-checkout"]', REGISTER, 'Register Account After Order Checkout'],
            ['[data-event="login-account"]', LOGIN, 'Login To Account Before Checkout'],
            ['[data-event="login-account-order-checkout"]', LOGIN, 'Login To Account During Order Checkout'],
            ['[data-event="login-account-quote-checkout"]', LOGIN, 'Login To Account During Quote Checkout'],
            ['[data-event="start-credit-application"]', APPLY, 'Start Credit Application']
        ],
        'Content Marketing': [
            ['[data-event="start-catalog-request"]', REQUEST, 'Start Catalog Request'],
            ['[data-event="start-white-paper-request"]', REQUEST, 'Start White Paper Request'],
            ['[data-event="start-utility-request"]', REQUEST, 'Start Worksheet Request'],
            ['[data-event="start-newsletter-subscription"]', SUBSCRIBE, 'Start Newsletter Subscription']
        ],
        'Shopping Actions': [
            ['[data-event="shop-categories"]', BROWSE, 'Shop By Category'],
            ['[data-event="shop-manufacturers"]', BROWSE, 'Shop By Manufacturer'],
            ['[data-event="search-site"]', SEARCH, 'Search Entire Site'],
            ['[data-event="search-category"]', SEARCH, 'Search Within Category'],
            ['[data-event="search-results"]', SEARCH, 'Search Within Results'],
            ['[data-event="add-to-cart"]', CLICK, 'Add Product To Cart'],
            ['[data-event="add-to-quote"]', CLICK, 'Add Product To Quote']
        ],
        'Quote Checkout': [
            ['[data-event="start-quote-checkout"]', CLICK, 'Start Quote Checkout'],
            ['[data-event="opc-quote-shipping-address"]', SUBMIT, 'Enter Shipping Address For Quote'],
            ['[data-event="opc-quote-shipping-method"]', SUBMIT, 'Select Shipping Method For Quote'],
            ['[data-event="opc-quote-complete"]', SUBMIT, 'Complete Quote Checkout']
        ],
        'Order Checkout': [
            ['[data-event="start-order-checkout"]', CLICK, 'Start Order Checkout'],
            ['[data-event="opc-guest-checkout"]', SUBMIT, 'Order Checkout As Guest'],
            ['[data-event="opc-shipping-address"]', SUBMIT, 'Enter Shipping Address For Order'],
            ['[data-event="opc-shipping-method"]', SUBMIT, 'Select Shipping Method For Order'],
            ['[data-event="opc-payment"]', SUBMIT, 'Enter Payment Information For Order'],
            ['[data-event="opc-complete"]', SUBMIT, 'Complete Order Checkout']
        ],
        'Quote Actions': [
            ['[data-event="edit-quote"]', CLICK, 'Edit Quote'],
            ['[data-event="remove-quote"]', CLICK, 'Remove Quote'],
            ['[data-event="convert-quote"]', CLICK, 'Convert Quote To Order']
        ],
        'Order Actions': [
            ['[data-event="start-rma-request"]', CLICK, 'Start RMA Request'],
            ['[data-event="start-reorder"]', CLICK, 'Start Reorder']
        ]
    };

    /*
        The `init` method gets things rolling. This is called when the
        `DOMContentLoaded` event fires (which happens after the HTML document
        has been loaded and parsed by the browser).
     */
    function init() {
        /*
            Below we assign each key ("Event Category") in the `events` object
            to an array using the `Object.keys` method. We then itterate through
            that array using the `forEach` method, executing an anonymous
            function that we pass the "Event Category" to as an argument. Inside
            that anonymous function, our module's `buildEvents` function is
            called with our category passed as the first argument and the array
            assigned to that category as the second argument.
         */
        Object.keys(events).forEach(function(category) {
            buildEvents(category, events[category]);
        });
    }

    /*
        The `bindListeners` method binds our Google Analytics "Custom Event"
        function created in the `buildEvents` method below as a callback to the
        DOM node whose selector is passed as the first argument (explained
        further in the in the comments for the `buildEvents` function below).
     */
    function bindListeners(selector, evt) {
        $(selector).on('click', evt);
    }

    /*
        The `buildEvents` method is called inside the `init` method. Its
        purpose is to construct the "Custom Event" function that gets called
        when an a user interaction takes place.
     */
    function buildEvents(categoryName, categoryEvents) {
        categoryEvents.forEach(function(item) {
            /*
                The `evt` variable holds our "Custom Event" function. This
                function is passed as an argument to the `bindListensers`
                function above. As noted above, this function gets called when
                a user interaction takes place.
             */
            var evt = function() {
                /*
                    We wrap our "Custom Event" funciton in a try/catch block.
                    This way, if the event fails (because Google Analytics
                    fails to load, etc), we can notify ourselves.
                 */
                try {
                    ga('send', 'event', categoryName, item[1], item[2]);
                } catch (err) {
                    /*
                        The `APP.logError` module, which is not covered in this
                        post, will notify us of an error.
                     */
                    APP.logError(err);
                }
            };

            /*
                Finally, we call the `bindListeners` function. This binds the
                function stored in `evt` as a callback to be executed when a
                user interaction takes place. The first argument contains the
                a selector (our `data-events`) attribute. The second argument
                is our `evt` callback function.
             */
            bindListeners(item[0], evt);
        });
    }

    /*
        Once the DOMContentLoaded event has fired, we execute our module's
        `init` function using jQuery's `ready` funciton.
     */
    $(document).ready(init);

}(jQuery));

Introducing Contrast Theme for Sublime Text

Contrast is a theme for Sublime Text born out of my frustration with inconsistent cross-language syntax highlighting. The purpose of Contrast is to reduce cognitive load by making color representative of how a program actually works, rather than just highlighting text.

Contrast Theme Language Support

I took a ground-zero approach when creating Contrast. No theme editor/generator was used. I started with, and will continue to build Contrast in raw XML. Currently, Contrast is focused on the languages below.

  • HTML
  • CSS
  • Sass
  • JavaScript
  • PHP
  • JSON
  • XML

My next step is to improve support for Sass. The current language definitions in Sublime Text for Sass are pretty awful. So, I need to create a better language file or find an open source one. The improved language file will provide the necessary Sass definitions to bind Contrast’s syntax highlighting rules to.

Contrast Theme Preview

Below is a screenshot of Contrast in JavaScript, where Sublime Text 3 does provide good language definitions. You will notice that function declarations and expressions are in blue, and function invocations are in light blue. While a relationship is established by all functions being blue, the different shades of blue imply a different context. Though subtle, this approach achieves the goal of reducing cognitive load by making it easier for developers to build a mental model.

Screenshot of a JavaScript module in Contrast Theme for Sublime Text
Contrast Theme JavaScript Preview

Lastly, my intent is to publish Contrast on Package Control when Sass support is better. For now, I’ll continue to use Contrast privately and fix errors and inconsistencies along the way. Feel free to download Contrast from GitHub.

Setup ionCube Loaders in WAMP

In order to develop sites on WAMP that have ionCube encrypted PHP files, you need to setup ionCube loaders in WAMP. Several years ago, I posted a popular screencast to my YouTube channel on the subject. I just upgraded to Windows 10 and took the opportunity to record another screencast on setting up ionCube loaders in WAMP.

The original screencast explains step-by-step how to setup ionCube loaders in WAMP using ionCube’s installation wizard. The new screencast does not use the wizard — it takes a more direct approach. While the installation wizard is recommended on ionCube’s website, the new approach is consistent with how you install any PHP extension in WAMP. Bottom line, both approaches will get the job done.

Setup ionCube Loaders Using The Wizard (the old)
Setup ionCube Loaders Without The Wizard (the new)

Visual Studio Code vs. Sublime Text

I want to start by giving high praise to the Visual Studio Code team at Microsoft. It’s an incredible product that I believe will only get better. The git integration, the task runner integration, JavaScript debugging, IntelliSense, and parameter hinting are all incredible features. Visual Studio Code (VS Code) is well designed and it’s fast. It strikes a near perfect balance between being feature rich and simple.

BUT…

Visual Studio Code is lacking in some key areas that matter to me:

  1. Color Themes
  2. Packages
  3. Language Support
  4. Key Bindings

VS Code Color Themes

At the moment, you are pretty well stuck with a handful of color themes provided by Microsoft. While it is possible to use Yeoman to build/convert a .tmTheme file for Visual Studio Code, in my experience it simply doesn’t work. I used Microsoft’s Yeoman generator to convert a couple themes on Color Sublime, and while there were no errors doing so, the syntax coloring was completely wrong compared to the same theme in Sublime Text. This is very frustrating. When you stare at a code editor all day, color really does matter.

Screenshot of JavaScript code using the same color theme in Visual Studio Code and Sublime Text
1337 Theme in VS Code and Sublime Text (JavaScript)
Screenshot of CSS (Sass) code using the same color theme in Visual Studio Code and Sublime Text
1337 Theme in VS Code and Sublime Text (Sass)
Screenshot of PHP code using the same color theme in Visual Studio Code and Sublime Text
1337 Theme in VS Code and Sublime Text (PHP)

VS Code Packages

With most developer tools, the strength of the community makes a huge difference in a product’s value proposition. This is certainly evident in Sublime Text where there are hundreds of packages available. While Sublime Text has felt old and unrefined for a couple years, the package ecosystem continues to set the editor apart. I don’t know a single Sublime Text user that runs the editor without multiple packages in use. The result of such a robust package ecosystem is that each Sublime Test user runs a tailored variant of base product. This is a huge plus for Sublime. It’s not all things to all developers, but it can [almost] be.

VS Code Language Support

I initially installed Visual Studio Code because I am about to start a Node.js project. The editor shines with Node – like it was made specifically for Node development. It’s 100% awesome. But I also develop for Magento and WordPress, both of which are built on PHP. To the same degree that Visual Studio Code is awesome with Node, it lacks with PHP. Though, this isn’t too big of a concern for me. Microsoft has made their current language focus clear, and as the product progresses, I’d imagine that language support will improve.

VS Code Key Bindings

Last and least, the available key bindings (keyboard shortcuts) just aren’t there. This is a problem that I am less confident will be resolved. While the critical key bindings are available, and customizing them is near identical to Sublime Text, the breadth of bindings that you can customize in Visual Studio Code is trumped by Sublime Text. I’m sure some developers don’t take advantage of keyboard shortcuts to the extent that I do. Again, this is an area where Sublime Text is not all things to all developers, but it can be. With Visual Studio Code, it’s flat out not.

VS Code vs. Sublime Text Conclusion

It’s good to periodically assess the features of an editor that you really depend on. That was the inspiration for this comparison. I am frustrated with Sublime Text’s lack of innovation. Working with Visual Studio Code for a few days made me realize how awesome an editor can be. I want to move to it. Unfortunately, Microsoft is just not there yet. Visual Studio Code will likely be my editor of choice in the future. For now, Sublime Text lives on as my canvas for another day.