My Thoughts

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.

2016 New Year’s Resolution

My professional goal in 2015 was to up my JavaScript skills. I focused on developing a much deeper understanding of the language and mastering its concepts. I feel good about the progress I made. While I still use (and love) jQuery, it’s no longer a crutch to mask my understanding of the language. In 2016 my JavaScript goal remains, but I am going to narrow my focus to a specific stack.

Right now there is so much innovation with JavaScript that it can feel overwhelming. It seems like every day there is a new framework, library or and build tool that the community clamors about. There is too much noise. The noise breaks focus, which impedes learning and hurts productivity. From an idealistic standpoint the stack should depend on the project. But for me, that’s just not practical. Time is the ultimate constraint, and I’d rather not spend it becoming a master of nothing.

Over the last couple months, I’ve done a fair amount of research and learning about different JavaScript technologies. Understanding their core methodologies has helped me isolate those that I feel have the most potential and will be the most fun to learn. So, in 2016 I’ve decided to focus on the following:

Each of these layers in the stack will come with a ton of new things to learn. By no means do I expect to become an expert by year’s end. I do expect however to be proficient with them, and I’m pretty excited about that!

Happy New Year 🙂

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)