JavaScript Leverage its Strengths to Eliminate its Weaknesses

Embed Size (px)

Citation preview

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    1/35

    JavaScript:Leverage it's strengths

    to eliminate it's weaknesses

    by P. LaNasa

    http://www.sitekickr.com/

    http://www.sitekickr.com/
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    2/35

    Contents

    1. Introduction

    2. Fun with JavaScript Numbers and Prototype

    3. Fun with JavaScript Strings and Prototype4. Drop and give me 20 units: enhancing the numeric

    5. Assertions are possible

    6. Caching function return values7. JavaScript organization for web development

    8. Avoiding inline JavaScript

    9. Using barricades for a more robust website10. Bonus: Ad optimization leveraging JavaScript to improve RPM

    11. Bonus: Optimize your JavaScript, save the environment

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    3/35

    1. Introduction

    I've been developing websites for over 10 years now, dabbling in almost every language andtechnology available, but also narrowing in on a handful of those that I find myself using on a daily

    basis. For many, that handful can be summed up in the popular acronym, LAMP (Linux, Apache,

    MySQL, Python/PHP/Perl). But, over the years, you really start to develop your own acronym that best

    describes your everyday development stack. For me, it's LAMCFJS (Linux, Apache, MySQL,ColdFusion, JavaScript). Of course, two of those don't fit the set, ColdFusion, because it requires a

    commercial license, and JavaScript because it's client-side. But that's my stack, and I'm stickin' to it.

    In recent years, I've developed a great fondness for JavaScript, and find myself blogging about it far

    more than any other topic. So, I thought I'd give this ebook thing a try, and piece together a few

    related posts. I hope you enjoy!

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    4/35

    2. Fun with JavaScript Numbers and Prototype

    One of the things that makes JavaScript so portable is it's intentionally minimal library of built-infunctions. By reducing the assumption that some off-the-wall function is available in a given version,

    we are nearly guaranteed that our scripts will work in any environment.

    However, this also means that a bit more work as to be done on the part of the developer to create basicfunctions that might otherwise be available in other languages. The good news is that the need for thesecommon functions has been lingering for many years, so most are readily available on the web.

    This lack of built-ins brings rise to another powerful feature of the language though. Because it's

    assumed that many functions will need to be created to operate on primitive data types, JavaScript

    provides us with the prototype property on function objects. Prototype allows us to easily add newmethods to built-in objects (classes) "on-the-fly". Meaning, if you've already instantiated a numeric

    variable, any method you add to the Number prototype will automatically, and instantly be applied.

    So, let's have some fun with Number's prototype!

    Is Number between x and y

    This function isn't going to win any awards, but don't you think it looks cleaner than: if(x >= 5 &&

    x = x && this.valueOf() x = 10;> x.between(5, 15);

    true

    Safe division (avoiding divide by zero issues)

    I get the divide by zero problem, you can't divide anything into 0 parts, unless you're Chuck Norris.

    But, as far as 90% my web apps are concerned, divide by zero isn't some cool abstract concept, they

    just want a return value of zero (or maybe N/A).

    But, instead, I need to perform checks every time I do a division operation, to make sure the result isn't"infinity", as returned by JavaScript when you divide by zero.

    I'm not a fan of having dozens of useless conditions floating around my code. Instead, I'd like to add a

    level of abstraction to the divide by zero concept, letting my code think that the result is always zero.Further, I'd like to encapsulate that into a function.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    5/35

    Number.prototype.safeDivideBy = function(x) {

    var result = this.valueOf() / x;

    if(result === Infinity) {return 0;

    }

    else {return result;}

    }

    > x = 10;

    > x.safeDivideBy(0);

    0

    Convert to currency string

    Your used to seeing currency related functions on the server-side, but with all this rich web application

    developer going around, a good set of currency-related functions might come in handy. Here's a start!

    Number.prototype.currency = function() {return '$' + (parseFloat(this.valueOf()).toFixed(2)).toString();

    }

    > x = 10> x.currency

    "$10.00"

    Random numbers

    I can't actually recall ever needing a random number between 0 and 1, but that's what JavaScript's

    random() function gives you. That's what any good random() function should give you. It's our job tobuild on that function for the specific needs of our application. In most cases, this means multiplying

    the result by a number, then rounding to an integer. Not bad, but this could be encapsulated into a

    function just as easily:

    Number.prototype.randomMax = function() {// return a random number with a maximum value of xreturn Math.floor(Math.random() * (this.valueOf() + 1));

    }

    > x = 10> x.randomMax();

    3

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    6/35

    Existence in an array

    If you've ever read "Code Complete" by Steve McConnell, you probably recall his discussion aboutProgrammingInto a Language. He was referring to the concept of tailoring a language to suit your

    development needs, rather than adjusting your needs to fit the limitations of the language. Prototype isone way we can achieve this within JavaScript.

    I used to do a fair amount of Python development, and came to love the in keyword syntax. It was soflexible in determining existence of one variable in a list or array. For example:

    'test' in 'testing'

    'test' in ['test', 'test1']

    9 in [9, 10, 11]

    I came to love it so much, that I just had to have it in my JavaScript development!

    Number.prototype.in = function(array) {var arrayLength = array.length;for(var i=0; i < arrayLength; i++) {

    if (array[i] === this.valueOf()) return true;}return false;

    }

    > myArray = [5,6,7,8]> x = 1

    > x.in(myArray) false

    > x = 7> x.in(myArray) true

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    7/35

    3. Fun with JavaScript Strings and Prototype

    More than a few reader's of my previous post on numbers pointed out that some of the functions Icreated were little more than semantically different from built-in functions. I agree, and that's okay.For

    me, adding functions to a built-in object's prototype doesn't serve to create cutting-edge string

    manipulation routines, but rather to reduce the complexity of my code, by encapsulating commonlyused algorithms into an easy-to-call function.

    Using a built-in object's prototype not only allows us to use a more intuitive syntax:

    newString = myString.awesomeFunction();

    But also helps us to maintain functional cohesion within our objects. Meaning, we don't need toscramble a bunch of unrelated functions together into a giant utility class, i.e.

    newString = util.awesomeFunction(myString);

    Not only does this lengthen our code, but it's disorganized. A function that does string manipulation hasno business in a class (object) that calculates the perimeter of a rectangle.

    Furthermore, it wouldn't make sense to create another class (object) to house string manipulationmethods when we already have the perfect one built in the String object.

    So, let's have some fun with String's prototype!

    Occurrences in a string

    Sure, this one's easy. Just perform a RegEx match. But, to someone else reading your code, it might not

    be immediately apparent what you're trying to do.

    myString = 'this is my string';

    numTimes = myString.match(/is/g).length;

    Drop that into a function on String's prototype and you've got more readable code at the very least:

    String.prototype.occurrences = function(substring) {var occRegEx = new RegExp(substring, 'g');return this.match(occRegEx).length;

    }

    > myString.occurrences('is'); 2

    Okay, that was not awesome. Hey, I'm just getting started!

    http://en.wikipedia.org/wiki/Cohesion_(computer_science)http://en.wikipedia.org/wiki/Cohesion_(computer_science)
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    8/35

    Markup

    How many times have you written or seen JavaScript like this, myself included:

    if(document.form1.name.value === '') {document.write('Oh no, you forgot your name?');

    }

    All those gurus are always telling you to keep JavaScript out of your HTML, so shouldn't the reverseapply? But, I really want to just spit out a boldface message. Here's a cleaner way:

    String.prototype.bold = function() {return '' + this + '';

    }

    document.write('Oh no, you forgot your name?'.bold());

    Language

    The previous couple functions walk the line of cohesion and usefulness, maybe even step over it. So,let's get back to the core of what a string is: typically a word or group of words in a given language.

    The String prototype is the perfect home for language functions.

    String.prototype.isQuestion = function() {var questionIdentifiers = ['when', 'where', 'why', 'what', 'who',

    'how', 'can'];

    // does the string contain a question mark?if(this.indexOf('?') !== -1) {

    return true;

    }// search keyword may indicate a question without explicitly

    specifying the question markfor(var i = 0; i < questionIdentifiers.length; i++) {

    if(this.indexOf(questionIdentifiers[i]) !== -1) {return true;

    }}

    return false;}

    We could use our new function to refine a user's search by conditionally returning results more likely toanswer questions, than to provide generic information:

    if(searchPhrase.isQuestion()){// favor search results in the knowledge base

    }else {// favor search results in the product store

    }

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    9/35

    Is it a Word?

    There's an unfair bias towards the numeric in computer science. Of course, it all stems from the factthat the CPU speaks numeric, while we humans speakstring. You can follow a gradual trend towards

    natural language-based syntax in popular development languages such as ColdFusion and Python. But,

    there really isn't much happening in terms of native support for natural language processing. I'm a littlesurprised by this, because I feel as if half of the applications that I develop require at least a very

    primitive form of natural language processing (search, form validation, speech recognition, etc.)

    Many languages offerisNumeric(), isDate(), or isArray() functions. But, how about

    isWord(), isVerb(), isCommand()?

    isCommand() could be used in searching algorithms (similar to isQuestion()) above. If a

    command is detected, the user might know more or less what they are looking for, otherwise, they may

    need a deeper level of assistance.

    isWord() could be used in form validation. If a user submits a field, validate that it's actually a word

    (or group of words). The definition of a word is subjective, but we'll make a few assumptions:

    1. A word does not contain spaces

    2. A word can contain only letters or the hyphen3. A word is less than 25 characters in length

    String.prototype.isWord = function() {if(this.length > 25) {return false;

    }return /^[A-Za-z\-]*$/.test(this);

    }

    A user submits a form which has fields for first and last name, so you validate against our new isWord()function:

    if(!firstname.isWord()) {alert('Is that really your name?');

    }

    Well, maybe it isn't. Many folks out there have a two-word first name. So, let's expand our String

    prototype to help out here:

    String.prototype.words = function() {return this.split(' ');

    }

    Now we are armed with the basics necessary to properly validate a first name:

    for each(item in firstname.words()) {if(!item.isWord()) {alert('Is that really your first name?');break;

    }}

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    10/35

    4. Drop and give me 20 units: enhancing the numeric

    When your high school gym teacher asked you to "drop and give me 20", did you ever have the guts to

    ask, "20 what?" Being the geeks that we are, such a question is perfectly valid, although in asking you

    might just earn yourself another 20 units of unwanted exercise! Although assumptions can be made in

    the real world about the unit implied by a certain context, the same can't be said for our code.Compilers and interpreters usually can't make assumptions like the one above based on context.

    Every programming language supports numbers natively, although they are almost always implemented

    as primitive types a place in memory to store a number, nothing less, nothing more. But as the

    opening paragraph suggests, numbers by themselves present very little information, unless they arepaired with a unit. We write our own code to deal with units, but most often the code is not consistent,

    both in checking the unit of a number, and converting to and from units.

    If you are developing in a dynamic language, such as JavaScript, you are offered an opportunity to

    enhance the way numbers are stored natively. The ability to "attach" a unit to a number can be gifted tothe Number data type. In the case of JavaScript, this is possible because a Number is an object, and

    most objects can be modified through JavaScripts prototype language feature.

    Enhancing the Number object with the prototype property:

    Number.prototype.setUnit = function(unit) {this._unit = unit;

    }

    Number.prototype.getUnit = function() {return this.unit;

    }

    The downside is that to leverage these new functions, we need to "formally" create a number object:

    myNum = new Number(56);myNum.setUnit('inches');console.log( myNum.getUnit() );

    On the flip-side, we still get to use our number as we're used to, it's functionally the same:

    myNum + 50 is still a valid arithmetic operation. The internal value of myNum is still 56.

    Adjusting the constructor for more meaningful code

    Sure, the technique above works great, but who really wants to initialize a Number object that wayevery time they want need to use an integer or float? What if we adjusted the Number object's

    constructor, to allow us to provide the unit as well? That would certainly make our additional efforts of

    creating a Number object more worthwhile, and perhaps make the code a little easier on the eyes:

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    11/35

    var oldProto = Number.prototype;Number = function(num, unit) {this.value = num;this.unit = unit;

    };oldProto.valueOf = function() { return this.value }Number.prototype = oldProto;

    Number.prototype.setUnit = function(unit) {this.unit = unit;

    }

    Number.prototype.getUnit = function() {return this.unit;

    }

    The real magic of the code above is the recreation of the valueOf() function on the Number object. If

    you've read an opinions on creating numbers with the new keyword, you might have found them all tobe against such a practice. But, much of their reasoning is that you loose the ability to perform

    operations on them. By redefining the valueOf function that JavaScript uses internally, we preserve thatcapability.

    However, it should be noted that the equality operation will no longer work! This is important toremember.

    x = new Number(30, 'inches');y = new Number(30, 'inches');

    x == ywill return false. This is because the equality operator does an object comparison and does

    not use the valueOf() function. I'd have to say that this is probably the only downside to this method,

    we're forced to compare against the valueOf() method:

    x.valueOf() == y.valueOf();

    Or, if we're feeling ambitious, adding a equals function to the Number object would serve our purposes

    equally well:

    x.equals(y);

    If you think this approach lends to code that's easier to read and write, using the code examples above,

    creating such a function should be relatively easy.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    12/35

    Avoiding inconsistent unit values

    As in the examples above, we certainly could allow string literals to be passed into the constructor. But,what happens when we use inches in one case,Inches in another case, and inch in yet another case?

    There are too many possible conditions to account for when testing against the units value. A simple

    solution to this is to provide a basic "units map":

    Number.units = { inches: 'in', millimeters: 'mi', feet: 'ft' }

    So, our new method of creating a Number object would look something like:

    x = new Number(30, Number.units.inches);

    But, what would prevent supplying string literals to the constructor? You could also perform some

    validation in the constructor:

    Number = function(num, unit) {this.value = num;

    var unitValidates = false;

    for each(value in Number.units) {if(value === unit) {unitValidates = true;break;

    }}

    // an assertion would make more sense here// unless we're accepting unit input from the userif(!unitValidates) {throw new Error(unit + ' unit is not allowed');

    return false;}

    this.unit = unit;};

    Dropping in the conversion functions

    Next comes the need to convert between units. There are two ways we can do this:

    Number.unitMap = [

    {Number.units.inches :{Number.unit.millimeters: 25.4,Number.unit.feet: 1 / 12 },

    {Number.units.millimeters:{Number.unit.inches: 1 / 25.4,Number.unit.feet: 1 / (25.4 * 12) },

    {Number.units.feet:{Number.unit.inches: 12,Number.unit.millimeters: 12 * 25.4 }

    ]

    https://www.sitekickr.com/blog/javascript-assertions/https://www.sitekickr.com/blog/javascript-assertions/
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    13/35

    1. Modify the Number object itselfNumber.prototype.changeUnit = function(unit) {this.value = this.value * Number.unitMap[this.getUnit][unit];

    }

    2. Use a function to return the converted value

    Number.prototype.convertUnit = function(unit) {return this.value * Number.unitMap[this.getUnit][unit];

    }

    Arguments against the arguments against adjusting built-in prototypes

    That double-negative is not a typo. As stated before, there are unlimited arguments against modifying

    built-in object prototypes. Some are valid, but most are nothing more than opinions about programmingstyle and convention.

    (26).doSomething();The above statement, agreeably is confusing and probably not a good practice. But, the method I

    discuss above doesn't allow for such "literal processing", as you are required to formally create aNumber object with the new keyword.

    var x = new Number(30, Number.units.inches);

    This statement can hardly be considered bad style or practice. It uses standard JavaScript objectcreation syntax, spells out clearly that we are using a modified version of the Number object, and

    encapsulates the use of units.

    At worst, we're trading a questionable JavaScript practice for many rock-solid software construction

    practices including abstraction and encapsulation.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    14/35

    5. Assertions are possible

    Assertions are a great development-time debugging tool. They allow us to raise a red flag whenever a

    condition occurs that should never occur. This is, of course, an entirely different strategy than error-

    handling, which is a production-stage, run-time tool that helps to improve a programs robustness by

    gracefully "surviving" after an expected error occurs.

    Assertion Example: The current object has been initialized before calling this routine

    Error-handling Example: User attempted to import a CSV file with 5 rows, instead of the expected 6

    rows

    Assertions are a handy self-disciplinary tool for the developer, but not all development languages

    support them natively. Unfortunately, JavaScript falls into this category. But, the concept behind theassertion is simple, and the code behind the concept is very easy to integrate into any language. Below

    is very basic assertion function that can be executed as a statement. It can make use of console logging

    or popup dialog alerts. But, the real magic happens when the function "detects" that the script is nolonger in development mode. In this case, it will rewrite itself to a very basic empty function to

    improve performance. Cool right!

    ASSERT = function(condition, message) {/* the checks below will only be performed in development */

    /* during production, if an ASSERT is left in place, it willcause the ASSERT function to rewrite itself to a void, empty functionto improve performance */

    /* you can assign appropriate values to local or dev parametersas makes sense by your application */

    if(local OR dev) {ASSERT = function(condition, message) {

    /* do nothing */}

    }else {

    if(!condition) {alert(message);// or console.log(message);throw new Error(message);

    }

    }}

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    15/35

    6. Caching function return values

    As web applications get more complex, more and more of the processing work is pushed to the client

    browser in the form of JavaScript code. We seasoned web developers earned our stripes in the server-

    side world, where our own web server executed the code. With this direct tie between a web browser

    and our precious server resources, caching was relied upon heavily, not only to improve siteperformance, but to reduce server load, which directly correlates to server operation costs. We had

    those two motivations to leverage caching.

    With the client-side revolution though, the web developer is seeing a decrease in server load, and an

    increase in client (browser) load. Sounds like a dream come true. But, this leads back to the motivationfor performance. We no longer need to rely on our own server resources for performance, but instead

    pass the buck onto the user's computer processing power.

    The issue isn't solely tied to developer motivation, but also to client-side language support. JavaScript

    doesn't offer a built-in caching solution. So, if we have a function which only expects 3 or 4 uniqueargument values over the script's lifetime, and that function happens to take 5 seconds to process, we're

    not doing our duty as programmers to put caching to work for the user. After all, we're still going to usethe client's memory for caching, what do we have to lose!

    Implementing a function return value cache only takes a few lines of code. Below is pseudocode that issyntactically correct JavaScript. I call it pseudocode because it really doesn't deal with all of the

    requirements that a proper cache should have (such as invalidating, lifetime, maximum size, etc). But,

    it introduces the concept and provides a foundation.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    16/35

    function Cache() {/* create the cache object as a singleton (only one instance

    allowed) */

    if(typeof Cache.instance === 'undefined') {Cache.instance = this;

    }

    var data = [ ]

    // we'll abbreviate cacheAwareCall as caCallthis.caCall = function(functionName) {

    var cacheCheck = this.load(functionName,this.caCall.arguments);

    if (typeof cacheCheck !== 'undefined') {return cacheCheck;

    else {var returnValue = window[functionName].apply(this,

    this.caCall.arguments)this.save(functionName, this.caCall.arguments,

    returnValue);return returnValue;

    }}

    this.save = function(functionName, argumentObject, returnValue) {// prepend item to cachedata.unshift({ fname: functionName, arguments:

    argumentObject, returnValue: returnValue });}

    this.load = function(functionName, argumentObject) {for(entry in data) {

    if(data[entry]['fname'] === functionName) {// we have a match on the function name// deepCompare is not implemented here, examples are

    throughout the webif(deepCompare(argumentObject, data[entry]

    ['arguments']) {return data[entry]['returnValue'];

    }}

    }

    return undefined;}

    return Cache.instance;}

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    17/35

    7. JavaScript organization for web development

    For those of you who have come across this post, and don't yet know about the object-oriented features

    of JavaScript, it will not carry much meaning. I used to be you, believing that JavaScript was only for

    validating web forms or making slick rollovers, and further-yet, that object-oriented programming is

    really only useful in game development or larger projects.

    I don't have the talent to persuade you otherwise, but these two guys do:

    Object-Oriented JavaScript: Create scalable, reusable high-quality JavaScript applications and

    libraries

    If you are in the first camp, not fully understanding the object-oriented nature of JavaScript, Ihave little doubt this book will open your eyes and present the language in a way you never seen

    before.

    Code Complete: A Practical Handbook of Software Construction, Second EditionIf you are in the second camp, not fully understanding the power of object-oriented

    development in general, this book is really a must have. It was a game changer for me many

    years ago, and the methodologies are language-independent, so anyone can benefit.

    With that being said, and assuming that if you're at this point in the post, you are familiar with OOdevelopment and JavaScript's OO features. You've probably authored a few JavaScript-based web apps,

    and are well aware of the challenges it presents when compared with traditional desktop OO

    development. Namely:

    There isn't a good way to organize classes and packages, and reference them from other classesand packages (unless everything is in one big file).

    Splitting classes and packages into multiple folders and files requires multiple HTTP

    connections to load all of the code

    The asynchronous nature of callbacks is useful, but can add a good deal of complexity to the

    even the simplest methods

    It's clear from a page load time perspective that condensing all of your classes into one file is the best

    choice. But having a few thousand lines of code in one file can make it difficult to locate the exactmethod you are looking for, as well as cause upload-time annoyances as the file grows larger and larger

    (if you are developing on a remote server).

    To overcome these issues, you can:

    1. Do your JavaScript development on your local machine. JavaScript is interpreted inside your

    web browser, so it does not require a web server.

    Another drawback for some is the same origin policy. If you are developing locally, browsersecurity restrictions disallow you from making cross-domain requests. To get around this

    though, many browser have initialization flags that turn this security feature off. For example,

    you can start chrome with the disable-web-security option.

    2. Use an IDE that recognizes JavaScript objects and organizes them into "classes, methods and

    properties" for you. I like Eclipse for this. The Project Explorer pane does a good job of

    classifying the objects, i.e.

    http://www.amazon.com/gp/product/1847194141/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1847194141&linkCode=as2&tag=site0e5-20http://www.amazon.com/gp/product/1847194141/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1847194141&linkCode=as2&tag=site0e5-20http://www.amazon.com/gp/product/0735619670/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0735619670&linkCode=as2&tag=site0e5-20http://www.amazon.com/gp/product/1847194141/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1847194141&linkCode=as2&tag=site0e5-20http://www.amazon.com/gp/product/1847194141/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1847194141&linkCode=as2&tag=site0e5-20http://www.amazon.com/gp/product/0735619670/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0735619670&linkCode=as2&tag=site0e5-20
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    18/35

    Although, I was a little disappointed to find that the project explorer doesn't catch on to this

    function definition syntax:

    myMethod = function() { }

    So, functions defined in this way, within a "class", don't show up in the explorer view.

    If you need to develop on a remote server, and prefer to separate your JavaScript classes and packages

    into a folder/file hierarchy as is familiar to compiled languages, you're not outta luck. We just have toget creative!

    In traditional OO languages, we are accustomed to included individual classes within packages on a"need-to-use" basis, i.e.

    import mypackage.myclass

    In JavaScript, we're kinda stuck with the tag, which is really only useful for loading in an

    entire JavaScript source file. That source file might contain 5 classes or 50 classes, all of which we

    must load, regardless of which ones we'll actually use. Because of this limitation, we typically includeall of our classes in one big file. It doesn't have to be this way!

    http://www.sitekickr.com/blog/wp-content/uploads/2012/09/eclipse-javascript.png
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    19/35

    We can extend JavaScript a bit, including just a few lines of code to emulate the package/class include

    methods found in our traditional languages. This of course, requires a few capabilities:

    The ability to dynamically load JavaScript files. When I say dynamically, I don't mean "at

    runtime", because there's no compiler, everything is at runtime. What I'm talking about is theability to load a JavaScript file from within JavaScript. We know we can do this by dynamically

    inserting a tag into our document, and providing it the appropriatesrc attribute.

    The ability to determine if a class has already been loaded, so we don't duplicate any efforts.This is possible with the JavaScript typeof operator. For our cases, we need to introduce the

    eval function, since we're dealing with a dynamic function name.

    A naming convention, so we know which JavaScript file to load, based on which package/class

    name was provided. By sticking to the convention of the filename carrying the same name asthe class, and the folder carrying the same name as the package, our little loader will always

    know which file to grab.

    As Nicholas Zakas points out, we can encapsulate the loading of an external JavaScript file into a

    function, and provide a callback to execute after the script has loaded, so our method call might looklike:

    loadScript("/mypackage/myclass.js", function(){//initialization code

    });

    Now, if we alter his script a bit, to use the naming convention we suggested above, the loadScript

    function would be more like:

    function loadScript(package_class, callback){var className = package_class.split('.').pop();if(eval('typeof ' + className) !== 'undefined'){

    callback();}

    var script = document.createElement("script")script.type = "text/javascript";

    if (script.readyState){ //IEscript.onreadystatechange = function(){

    if (script.readyState == "loaded" ||script.readyState == "complete"){

    script.onreadystatechange = null;callback();

    }

    };} else { //Others

    script.onload = function(){callback();

    };}

    script.src = '/' + package_class.replace(/\./g, '/') + '.js';document.getElementsByTagName("head")[0].appendChild(script);

    }

    http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    20/35

    Essentially, we are replacing the dot notation with folder notation, so by callingthis method:

    loadScript('Mypackage.Myclass', function(){//initialization code

    });

    We are actually loading the /Mypackage/Myclass.js file. The Myclass.js file contains a Myclassfunction, which upholds our naming convention. Notice also, in the opening lines of the new loadScript

    method, we check to see if the class has already been loaded.

    But, what if we want to load multiple classes, and have our callback fire only after all of the external

    scripts for those classes have been loaded? One possibility would be to create an array of scriptelements, load them all, then with each onload event, check to see if all scripts have been loaded:

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    21/35

    function loadScripts(packages_classes, callback){var scripts = [], scriptCount = packages_classes.length;

    for(var i = 0; i < scriptCount; i++ {var className = package_class.split('.').pop();if(eval('typeof ' + className) !== 'undefined'){

    scripts[i] = {loaded: true};

    }else {

    scripts[i] = {loaded: false};}

    scripts[i].script = document.createElement("script")scripts[i].script.type = "text/javascript";

    if (scripts[i].script.readyState){ //IEscripts[i].script.onreadystatechange = function(){

    if (scripts[i].script.readyState == "loaded" ||scripts[i].script.readyState == "complete"){

    scripts[i].script.onreadystatechange = null;scripts[i].loaded = true;if(checkAllLoaded()) {callback();

    }}

    };} else { //Others

    scripts[i].script.onload = function(){scripts[i].loaded = true;if(checkAllLoaded()) {callback();

    }};

    }

    scripts[i].script.src = '/' + package_class.replace(/\./g, '/')

    + '.js';document.getElementsByTagName("head")

    [0].appendChild(scripts[i].script);}

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    22/35

    // private function - check if all scripts have been loadedvar checkAllLoaded = function() {for(var i = 0; i < scriptCount; i++ {

    if(!scripts[i].loaded) {return false;

    }else {return true;

    }}

    }}

    I have not tested the above code, at all! It's meant to be more theoretical. But, it would appear that

    loading multiple external files, and waiting for a callback is possible. So, a method like this, very clean

    and consise is actually possible in JavaScript!

    loadScripts(['Mypackage.Myclass', 'Mypackage.Myclass2','Myotherpackage.Myotherclass'], function(){

    // tie it all together here!

    });

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    23/35

    8. Avoiding inline JavaScript (and CSS)

    Every HTML page consists of three major components:

    The skin/template (including meta data)

    HTML tags used to wrap the content and provide information about the page

    The content

    Text marked up with HTML tags

    The presentation

    CSS rules and JavaScript code

    The skin/template should be separated from the content on the server-side, using a framework or layout

    method as described in my post on Site Structure. The presentation, however, needs to be separated onthe client-side, using , , and tags. This is one of the oldest and most-commonly-

    spoken-of web development practices, and I'd like to go into detail on why this is such a good idea.

    Essentially, what separation of content and presentation means is that we are to avoid embedding inline

    styles and scripts in our HTML content. For instance, this is a prime example of what not to do:

    click

    Markup like this is found all over the web, often as a result of inexperienced web coders using

    graphical editors, but experienced web developers share the blame too. It's all too easy when 5 o'clock

    comes around and your taking every shortcut possible to get out the door, to forgo creating a style class,

    and instead just drop those styles right into the HTML tag.

    Instead of just frowning on the practice, let's look at a few reasons why this separation is so important:

    1. Referencing bare HTML content is more difficult

    This reason doesn't present itself right away. It usually comes into play after a website has beenlaunched, and it's content is consumed by services or clients other than a web browser. Because

    CSS and JavaScript is only useful to web browsers, anything else which references the content

    will either ignore it, or be negatively affected by it. You are, in essence forcing non-browsers toabsorb presentational information when it carries no meaning.

    Search engines do a great job of ignoring the presentational items when they index your pages,

    but it doesn't mean they like it.

    2. Global presentational changes are difficult

    This one becomes apparent if you have more than 5 pages on your site, each with inlinepresentational elements. If you have a page title styled as such:

    My page

    heading

    https://www.sitekickr.com/blog/layouts-templates/https://www.sitekickr.com/blog/layouts-templates/
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    24/35

    Then, at some point down the road, you decide that green isn't really the look you were going

    for with page titles, you need to manually adjust all of your HTML files, to make the inline style

    adjustment. This difficulty is compounded with JavaScript, as often times your editor's global

    file search/replace feature will be difficult to use against a multiline search.

    3. Future-proofing

    tags currently validate inside elements (with XHTML you need to use the ugly //!

    [CDATA[ trick), but there may be a time when they don't, as the currently does not.

    4. Context

    During a presidential race, we hear phrases spoken by candidates, but out of context. The phrase

    may have carried meaning in the context of the content that surrounded the phrase, but alone, itcarries no meaning or just makes them look bad. The same happens with CSS!

    To illustrate, let's say we have a block of content that we want to emphasize heavily by placing

    a 50 pixel black border around it, using inline CSS:

    This content is soimportant that mobile users need to suffer!

    This may present well on a 1024 pixel wide desktop browser, but on a mobile device, the borderitself will take up nearly half the screen. To avoid this, we would typically have separate CSS

    files for mobile and desktop. But, there is no such separation when we use inline CSS.

    To illustrate in a different way, let's say we have the following inline CSS:

    This is a red link

    If this content is loaded on a device with a black & white screen, the red link styling is useless

    and only served to make the content itself take longer to download.

    5. Team environment

    If you work in a team, it's likely that you have one team member dedicated to content (HTML),

    another to style (CSS), and still another to interactivity (JavaScript).

    If you are absent version control and a "check-in" procedure as so many small operations are,

    the logical course of action is to restrict access to HTML files to the person who edits theHTML, CSS files to the person who manages the CSS, etc. This serves to prevent one person

    from overwriting another's work if they are both accessing the same file at the same time.

    That system works well, unless you have CSS and JavaScript embedded in your HTML files. In

    this scenario, the person who manages CSS needs to say, "Hey Bob, can you close the file yourworking on for 20 minutes while I edit the inline CSS? When I'm done, don't forget to load the

    file from the server again so you don't overwrite my changes. Thanks Bob, you're the best, sorry

    for wasting 20 minutes of your day!"

    http://javascript.about.com/library/blxhtml.htmhttp://javascript.about.com/library/blxhtml.htmhttp://javascript.about.com/library/blxhtml.htmhttp://javascript.about.com/library/blxhtml.htm
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    25/35

    6. Markup to content ratio (bad for search engines)

    This one has been preached about by SEO wizards for years, so I apologize for duplicating it

    here. However, the list wouldn't be complete without it. Not only does inline style and script

    increase page load time, it increases the download time for search engines who are just lookingfor raw content. In effect, a search engine has downloaded additional information that it needs

    to discard anyway. This negatively affects how search engines position your site in two ways:

    The content vs. markup ratio. It has been suggested the search engines frown when the

    amount of markup exceeds the amount of content by an undetermined amount (the ratio,of course, being dependent on the search engine). Without knowing the ideal ratio, it's a

    wise practice to keep markup to the absolute minimum required. This includes, of

    course, eliminating inline style and script when possible.

    Page load. Recent evidence suggests that Google (and perhaps other SEs) factors your

    page load time into it's ranking algorithm. Essentially, with all other things being equal,

    a site with a faster page load will be ranked higher. As touched upon in the point above,inline style and script increase page load time.

    7. Performance

    We've touched on how inline style and script can negatively affect performance, but there'sanother side to that. Housing all of your CSS and JavaScript in external files can actually

    improve performance drastically. The magic comes from browser caching. A typical web site

    frequently updates content, but rarely touches style and interactive areas. With this in mind,most web hosting configurations are set to direct web browsers to cache CSS and JavaScript

    files.

    By caching these files in the browser, they do not require another HTTP connection to

    download them from the server. This post goes into more detail onbrowser caching.

    With these seven reasons comes a compelling argument against the use of inline style and script, but by

    no means am I saying it is incorrect to do so. It is currently valid, and in very simple sites, may actually

    improve performance. In some cases, you can apply an inline style without coming in conflict with any

    of the reasons above. But, avoiding inline style and script usually leads to many years of happy andhealthy web coding!

    https://www.sitekickr.com/blog/browser-caching-basic/https://www.sitekickr.com/blog/browser-caching-basic/
  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    26/35

    9. Using barricades for a more robust website

    You hear the term robustthrown around loosely."Hey Bob, that new app is gonna be robust, right?"

    "Oh yeah Steve, I'm all over that robustness."

    But how many people really understand what they're promising? I certainly didn't used to. If youdictionary.com the word robust, you are told that it meansstrongandhealthy. If you try to translate

    that meaning to software quality, it become a little ambiguous.

    Strong. Does that mean the software can process a lot of data? Or can support a large amount of

    concurrent users?

    Healthy. Are we talking about how many errors occur within the software? Health is perhaps moreclosely related to robustness, but not exactly.

    When talking about software, robustness is how well your code deals with errors, and whether or not

    the software can continue to run in the wake of an error. Using the healthiness analogy: Your softwaremay be in perfect shape and run error free 99.9% of the time, but how well does it cope when it catchesa cold? If your software decides who your best friend is on Facebook, no harm done if an error shuts

    down the program. But, if your software operates a pacemaker, that .1% probability of an error really

    shouldn't shut anything down!

    Different web technologies offer different solutions, some not quite as apparent as others. But, beyondsyntax and keywords, there are methodologies that provide robustness. The general approach needs to

    be a little different when working with client-side code as opposed to server-side. On the server side we

    have more complete error information, as well as logging and notification options that just aren'tpossible (or are more much more difficult to achieve) on the client side.

    Server-Side

    On the server side, the first step is to decide what the barricade protects. For instance, if you have atwo-column website in which both columns are dynamically generated by your server-side code, you

    might want the content column to be entirely unaffected by any errors that occur in the sidebar. A

    popular example of this issue occurs within any given WordPress blog. Depending on your PHP errorsettings, an error in your sidebar will "take down" the entire page. With this possibility, it's in your

    user's best interest to barricade the sidebar from the rest of the site. For that matter, perhaps the footer

    as well.

    We can do this with our old friend the try/catch block. By wrapping the entire sidebar code in a

    try/catch, we prevent any and all errors from affecting the rest of the site. This still allows our

    more "fine-tuned" errors to do their job of properly logging and notifying the user of any errors. But,

    we also have the added comfort of being able to log errors from within the "master" catch block.

    This doesn't even mention the level of security gained by not exposing error information to potential

    hackers.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    27/35

    JavaScript

    It seems like every time I come up with a good, solid server-side methodology, it doesn't transfer to

    JavaScript! With JavaScript, errors are not displayed front-and-center to the user. They are tucked away

    behind a small warning icon in the corner of the browser. But, that doesn't mean they can't do just asmuch harm. As with server-side code, one error in your script and that's it, execution stops.

    Of course, we have the same try/catch capability. We could easily wrap an entire chunk of JavaScript ina nice big try/catch. But, how many of us want to wrap our entire script in a try/catch? JavaScript just

    doesn't have the useful error reporting that server-side languages have, such as context, line number, etc(some browsers support line number). This would be a debugging nightmare, as the errors would no

    longer be picked up by our browser console our true friend in the debugging effort.

    JavaScript does, however, treat it's "turn-me-on" tag a little differently than server-side-languages.

    "turn-me-on", of course, refers to the tag saying to the browser, "start parsing JavaScript!".

    What were you thinking?

    The tag is self-contained, error-wise. It is an errorbarricade from the rest of the

    tags. Server languages like PHP or ColdFusion don't provide such a barricade. You can

    have 30 directives in one PHP file, even divide them up across multiple files. But an error inone ruins the whole batch. Whereas in JavaScript, an error in one tag kills the entire script

    within, but doesn't affect the other tags at all.

    So, how is this useful?

    var x = something; // 'something' is not defineddocument.write('Why won\'t my message display, sadness');

    pacemaker.keepOnWorking();document.write('I am unscathed by the errors in my document\'s

    other script tag!');

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    28/35

    10. Bonus: Ad optimization leveraging JavaScript to

    improve RPM

    I love highway billboards, and I think they're really effective, at least on me. I do however, wish they

    were a bit more dynamic. For one, I've always wondered why they don't include a giant QR code thatpassengers can try to snag with their phone while passing by. If anyone uses this idea, I want 10%. It's

    probably been done a thousand times, and I just need to get out more! Okay, digressing from the

    subject of the article a bit.

    Billboards are great, but they only work while driving in one direction, and if you don't get a chance totake it all in, there's no going back. On the web, the browser scroll bar is analogous to the highway.

    Once a user scrolls an advertisement out of view, not only is it no longer visible, but it certainly can't be

    clicked. But, no asphalt was laid, and there are no laws against scrolling back up. Yet, how many usersdo you think will actually scroll up to see if they missed any good advertisements? We have more

    opportunity to keep our ads within the view of our website visitors, by using JavaScript. Some of the

    techniques are so basic that you'll wonder why you haven't been doing them a long time ago.

    Keeping ads in view

    You don't need a marketing guru to tell you that an advertisement holds no value if you can't see it.There's absolutely no dispute about that fact that you can't click an advertisement if it is not in view. If

    you only have one or two ads on your site, it's important to make sure they are always visible, without

    being intrusive.

    As many ad optimization techniques suggest, keeping ads close to readable text is a good idea. On thisblog, you'll notice that I have one floated in or around the third paragraph. But, what happens when you

    scroll down beyond the third paragraph. The advertisement becomes useless.

    Now, I certainly don't want to annoy my readers, so moving the ad within the content area would not be

    the way to go. It would cause content to shift as line-wrapping changes to support the ad that has beenfloated next to it. I instead opted to move the ad down below the right sidebar when it is scrolled out of

    view. This type of movement is accomplished by wrapping the advertisement code in a

    element, then moving that with jQuery. In the example below, I have wrapped the AdSense ad

    code in a element with an id ofpost-inline-ad.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    29/35

    $(window).scroll(function(){if(siteKickr.isScrolledIntoView($('.entry-content

    p').first().next().next())) {if($('#post-inline-ad').hasClass('sidebar')) {

    // if ad is in sidebar, move back to paragraph$('#post-inline-ad').removeClass('sidebar');$('.entry-content p').first().next().next().after($

    ('#post-inline-ad'));}

    }else {

    if(!$('#post-inline-ad').hasClass('sidebar')) {// if ad is not in sidebar, move to sidebar$('#post-inline-ad').addClass('sidebar');$('.widget-container').last().after($('#post-inline-

    ad'));}

    }

    });

    siteKickr = {isScrolledIntoView: function(elem){

    var docViewTop = $(window).scrollTop();var docViewBottom = docViewTop + $(window).height();

    var elemTop = elem.offset().top;var elemBottom = elemTop + elem.height();

    return ((elemBottom =

    docViewTop));}

    }

    This method isn't quite as hardcore as keeping the advertisement in the view regardless of scroll

    position, but it gives the user another opportunity to view the ad, where it may previously had not beenin a recognizable position.

    Fixed Positioned Element, the CSS way

    Of course, there's always the simple, yet effective CSS solution:div#my-ad-wrapper { position: fixed; top: 100px; left: 0; }

    Thefixedvalue of the position style specifies that an element remains in the specified position, even ifthe user scrolls. It's similar to the absoluteposition, except that an absolutepositioned item will scroll

    with the rest of the static content.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    30/35

    Hey, look over here

    Most metrics divide the number of ad impressions by the number of clicks to determine how well

    optimized your ad placement is. That works well, but there's another metric to consider is the total

    time-on-page for your visitors in relation to ad clicks. If a visitor sits on one page of your site for anhour that's a measure of success in many ways, but if they don't click on a single ad in that hour, then

    that visitor may not be as valuable to you as all the other metrics lead you to believe.

    If you are a door-to-door vacuum salesperson, asking people for 5 minutes of their time, how

    successful would you be if you spent 1 minute giving your pitch, then just stared at them for theremaining 4 minutes.The same thing happens when a visitor loads a page on your site, sees the

    advertisements unfold before their eyes, then continues on to read the page content for 5 minutes.

    You can keep your visitor engaged in the opportunity to click advertisements by displaying them again

    after a certain period of time, unobtrusively. I emphasize the term unobtrusively, as the best way toannoy your visitor would be to surprise them with an advertisement pop-up right over the text they are

    reading. But, if you pull a "sidebar surprise", you won't offend your visitor.

    Check your analytics tool for pages with high "Avg. Time on Page", to determine which pages would

    most benefit from this method:

    Then, let's again put JavaScript to work for us, in this case to reveal an advertisement in the sidebarafter the user has been on the page for 60 seconds:

    The HTML

    X

    Thanks for your interest in this article. How about a break to

    check out the awesome deals from our friends at:

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    31/35

    The CSS

    #timed-ad {position: fixed;top: 300px;right: -270px; /* account for width and padding */

    width: 250px; |padding: 0 10px;border: 1px solid #000;border-radius: 5px 0 0 5px;background: #eee; }

    #timed-ad .close {float: right;margin: 0 -10px 0 0;padding: 5px 8px;color: #fff;background: #555;

    cursor: pointer; }

    The JavaScript (jQuery)

    $('#timed-ad .close').click(function() {$(this).parent().remove();

    });setTimeout(function() {$('#timed-ad').animate({ right: -1 }, 2000);

    }, 60000); // 60 seconds

    Making use of empty real estate

    You've no doubt noticed the trend towards wide screen desktop monitors. A website afforded this muchwidth could easily reduce the vertical scrolling necessary to see all of it's content. But, most don't take

    advantage, and for good reason. Many users are still on 1024768 monitors. And, even if we used a

    responsive layout, to use whatever width is offered by the screen, we still wouldn't want content to span

    the full width of a widescreen monitor, it would be difficult to read.

    So, what do we do with these large "gutters" on either side of the content. Since we can't use them for

    the site content, we might consider using them for something that doesn't affect the purpose of the site

    if they can't be seen: advertisements. You could use any number of CSS techniques to force these adsinto the widescreen gutters of the site, but JavaScript certainly provides the most flexibility.

    With JavaScript, you can introduce the condition to only display the gutter ads if the site width is

    greater than 1400 pixels, for example.

    This is, arguably, the least intrusive form of banner advertising on a website. It doesn't intrude on the

    content area at all, and users are more than welcome to reduce their browser width if they don't want tobe "bothered" with the advertisements.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    32/35

    The implementation of this method is simpler than the other methods, so I'm going to break my own

    rules of separating content, css & script, and package it all up into a small piece of jQuery:

    $(window).resize(function() {if($(window).width() > 1400) {

    /* widescreen - show gutter ad */if($('#left-gutter-ad').length === 0) {

    $('body').append('My ad code goeshere');

    }}else {

    $('#left-gutter-ad').remove();}

    });

    $(document).ready(function() {$(window).resize();

    });

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    33/35

    11. Bonus: Optimize your JavaScript, save the environment

    I'm not a tree-hugger, but I'm conscious about the environment. I recycle, drive a 4-cylinder, try to eat

    local/organic, and try not to dump paints and varnishes down the kitchen drain. But,I never really

    stopped to consider my direct connection to the environment through my coding practices.

    When we think about abstraction, we usually don't go further than the operating system or thecomputer processor. We run a high-level language function, it's converted into dozens of low-level

    language statements, then hundreds of lines of machine code, which is run by the processor. But, all

    that happens under the condition that the processor has power. Let's take a look at the levels of

    abstraction that extend beyond your CPU.

    Plants

    Coal was formed from the remains of vegetation that grew millions of years ago. The plants whichformed coal captured energy from the sun through photosynthesis. This energy is used to create the

    elements within plant tissue. The element most important for us being carbon, which gives coal most of

    its energy. No environmentally negative factors here.

    Coal

    Of course, coal is not the only form of energy used to generate electricity, but it's the largest in the US.

    Coal power stations have machines that convert the heat energy from the combustion of coal intomechanical energy, which then powers the electric generator. It's the byproducts and wasted heat

    energy from this process that causes the negative environmental effects. The process is not 100%

    efficient. Those inefficiencies aren't bottled up, they're sent to our air, lakes and rivers.

    On average, a ton of coal generates 2,460 kilowatt-hours of electricity. Let's make that simpler:

    1 kilowatt-hour of electricy = .81 pounds of coal

    The Kilowatt

    We Americans aren't fluent in the metric system, but we know the Kilowatt better than any other unit of

    measurement when it comes to electricity. Why? Because that's what we see on our electric bill, theKilowatt-hour. But, lets not forget that the kilowatt-hours we use at home don't directly translate to the

    kilowatt-hours generated at the power plant. A certain amount of energy is lost in the transmission over

    the power lines.

    So, how does this translate to our computer's CPU power demands? A kilowatt-hour may be enough topower your light bulb for an entire day, but a CPU is vastly more complex. A light bulb performs one

    operation consistently, from the time you turn it on, to the time you turn it off. Calculating it's energyusage is straightforward. But, your computer's processor is more dynamic.

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    34/35

    The CPU

    CPU's used to maintain a more steady power consumption, but today's CPU is more energy consciouswhen idle. The big question is, "how much energy is saved when it's idle, compared to when it's

    working?" Apparently, this is not an easy question. It, of course, depends on who you ask, what the rest

    of the system is doing, and which processor. Many forums I visited seemed to suggest that an Intel I7

    would drop to 75 watts, from 95 watts when at idle.

    I also had difficulty finding out exactly what idle means. Is the processor idle between each sequential

    instruction sent its way? Or does it require a length of time before it settles down into it's idle state?

    Again, a solid conclusion wasn't reached. So, for this article, I'm going to make the following

    assumptions:

    The difference between idle and working = 20 watts = .02 kilowatts

    Additional Kilowatts used for 1 CPU instruction = the number of hours the instruction takes * .02

    I'm emphasizing the word additional, because the CPU uses power whether it's processing an

    instruction or not.

    The next question: How long does a CPU take to execute one instruction? It varies of course, so let'sagain use the Intel I7. Wikipedia says 82 billion instructions per second! You might be thinking, whyare we possibly concerned with power consumption when we can process 14.7 quadrillion instructions

    for just one measly kilowatt-hour!

    1 Kilowatt-hour, we remember, is created by the combustion of .81 pounds of coal.

    1 pound of coal gets us 18.2 quadrillion instructions. Good job coal, your not so bad after all. But, holdon, we haven't worked our way through the remaining levels of abstraction. How much does 18.2

    quadrillion instructions really buy us?

    JavaScript

    Huh, how did I get to JavaScript? I skipped machine code, assembly language, the OS, the browser

    environment. I decided to do this for the dramatic effect of showing how many CPU instructions arerequired for a simple JavaScript statement.

    var x = 1 + 1;

    I'm now thinking to myself, "how do I begin to determine how many machine code instructions thatlittle statement took?"

    I intentionally avoided anything user-interface or input related, to simplify this task.

    We first need to find out what JavaScript "sits on". Until Google's V8 engine, JavaScript was

    interpreted, and still is in most browsers, by a JavaScript engine. The first JavaScript engine,SpiderMonkey, was written in C++.

    C++

    What does it take for C++ to run a JavaScript statement such as the one above. I'd have to imagine thatthis particular statement is one-to-one. C++ allows us to declare and initialize a variable in one line of

    code, even if that initialization involves arithmetic.

    int a = 1 + 1;

  • 7/30/2019 JavaScript Leverage its Strengths to Eliminate its Weaknesses

    35/35

    Assembly Language

    .datax: .word 1y: .word 1a: .word 0

    add a,xadd a,yint 21h

    Is the above proper assembly langage? No. Will it work? Probably not. I don't know Assembly

    Language, I just wanted to illustrate the number of instructions required to perform a simple operation.

    In this case, it's likely that each assembly code instruction will produce one line of machine code. So,

    the most basic JavaScript statement might translate to at least 7 lines of machine code. I'm talkingabout a statement that involves nothing but the processor and RAM (no display, peripherals, disk drive,

    etc). A more complex statement, such as document.write(), may actually consist of hundreds of

    machine instructions. So, we can easily see how inefficient JavaScript code is orders of magnitude

    more inefficient when you look at it from a machine code standpoint.

    But this still doesn't really mean anything. It's too difficult to relate additional lines of machine codedirectly to environmental impact! But, what if we convert that into more recognizable metric, time.

    If a set of poorly optimized JavaScript statements takes 100 milliseconds to run, and the optimized

    version of that same code takes 50 milliseconds to run, you are keeping that processor busy for 50

    milliseconds beyond what is necessary.

    50 milliseconds = .05 seconds = .000014 hours

    .000014 hours * .02 additional kilowatt hours required by the active CPU = .00000028 kilowatt-hours

    So, an additional .00000028 kilowatt-hours are required by your one inefficient algorithm.

    Not bad, that only means .00000022 pounds of coal. But, that's just one algorithm, in one page load, byone user.

    If your website gets 10,000 page loads today, that number hops up to .0022 pounds of coal wasted.

    Yikes, that's getting a little scary!

    Over a year, that turns right back into that original .81 pounds of coal, enough to generate 1

    kilowatt-hour of electricity, to power the additional CPU cycles required by that same inefficient

    algorithm.

    Again, that's just ONE algorithm, on one page on the web.

    Now, my brain is exhausted from all this math, but multiply this by the number of pages on the web,

    and the number of poorly written algorithms on a page, and you've got an awful lot of coal!Who votes that the windows task manager should have another column for "Coal Burned"!

    http://www.sitekickr.com/