Category Archives: JavaScript

JavaScript Best Practicies : Performance Calculation

Test the speed of code with console.time

var firstRegimentNewbs = ["Grimble Horsehead", "Jark Winterborn", "Bunder Ropefist",
                          "Ernst Breadbaker"];
var firstRegimentKnights = [ *...tons of Knight objects...* ];
console.time("Time to add " + firstRegimentNewbs.length + " Knights");
for(var i = 0, x = firstRegimentNewbs.length; i

Multiple timers can run at one time.

var firstRegimentNewbs = ["Grimble Horsehead", "Jark Winterborn", "Bunder Ropefist",
                          "Ernst Breadbaker"];
var firstRegimentKnights = [ *...tons of Knight objects...* ];
var secondRegimentNewbs = ["Jenner Pond", "Tar Backstrand", "Cromer Treen", "Stim Lancetip",
                           "Vorn Sharpeye", "Rack Leaflets", "Bruck Valleyhome", "Arden Follower"];
var secondRegimentKnights = [ *...tons of Knight objects...* ];
console.time("Total completion time");
for(var i = 0, x = firstRegimentNewbs.length; i

Retrieving and using numerical time data
To accurately generate numerical data we can manipulate, we'll first examine the JavaScript Date object.
Placing a + unary operator in front of Date object variable asks for the specific value in milliseconds.

var rightNow = +new Date();

Implementation of speed test class

function SpeedTestClass(testImplementation, testParams, repetitions) {
  this.testImplementation = testImplementation;
  this.testParams = testParams;
  this.repetitions = repetitions || 10000;
  this.average = 0;
}
SpeedTestClass.prototype = {
  startTest: function() {
    var beginTime, endTime, sumTimes = 0;
    for (var i = 0, x = this.repetitions; i < x; i++){
      beginTime = +new Date();
      this.testImplement( this.testParams );
      endTime = +new Date();
      sumTimes += endTime - beginTime;
    }
    this.average = sumTimes / this.repetitions;
    return console.log("Average execution across " + this.repetitions + ": " + this.average);
  }
}

How to use created class:

var firstRegimentNewbs = ["Grimble Horsehead", "Jark Winterborn",
                          "Bunder Ropefist", "Ernst Breadbaker"];
var firstRegimentKnights = [ *...tons of Knight objects...* ];
var listsForTests = [ firstRegimentNewbs, firstRegimentKnights ];

var BP = function ( listOfParams ){
  for(var i = 0, x = listOfParams[0].length; i < x; i++) {
    listOfParams[1].push(new Knight(listOfParams[0][i], 1));
  }
};

var BPtest = new SpeedTest(noBP, listsForTests, 100000); 
BPtest.startTest();

JavaScript Best Practicies : Performance

Loop Optimization

console.log("You've found the following necklaces:");
for(var i = 0; i < treasureChest.necklaces.length; i++) {
  console.log(treasureChest.necklaces[i]);
}

For each potential loop cycle, the program will need to find and retrieve:
1. the value of i
2. the treasureChest object
3. the necklaces property
4. the array pointed to by the property
5. the length property of the array

1st optimization: Use "cached values" to curtail lengthy, repetitive access to the same data.

console.log("You've found the following necklaces:");
var x = treasureChest.necklaces.length;
for(var i = 0; i < x; i++) {
  console.log(treasureChest.necklaces[i]);
}

Memory access during loop control now only needs to:
1. retrieve the value of i
2. retrieve the value of x
Then, add in our one-time cost in creating x:
1. creating the variable x in memory.
2-5. the 4 steps finding the value of length

Some arithmetic calculations:
5 steps x (10,000 executed loops + 1 check to stop) = 50,005 memory access steps

2 steps x (10,000 executed loops + 1 check to stop) = 20,002 memory access steps
+ 5 extra steps for x = 20,007 memory access steps

~30,000 steps of savings in result!

2nd optimization: place new control variable inside the first loop parameter.

console.log("You've found the following necklaces:");
for(var i = 0, x = treasureChest.necklaces.length; i < x; i++) {
  console.log(treasureChest.necklaces[i]);
}

3rd optimization: avoid repetitive access of a property within an object

console.log("You've found the following necklaces:");
var list = treasureChest.necklaces;
for(var i = 0, x = treasureChest.necklaces.length; i < x; i++) {
  console.log(list[i]);
}

Note: Now we've avoided the extra step of accessing the treasureChest in each cycle.

Script Execution

Problem: Scripts encountered high in the or tags of an HTML page can have adverse effects.
Solution One: Scripts that are not essential to immediate loading of the page should be moved as low as possible.
Solution Two: With external files, the HTML5 async attribute will allow the rest of the page to load before the script runs.

Short Performance Tips

USE A PROTOTYPE FOR SHARED STUFF:
Beware of loading up individual objects with code that easily could be held and sourced elsewhere.
Candidate for optimization:

function SignalFire( ID, startingLogs ){ 
  this.fireID = ID;

  this.logsLeft = startingLogs;
  this.addLogs = function ( numLogs ){
 
    this.logsLeft += numLogs;

  }
  this.lightFire = function () {
 
    alert("Whoooosh!");

  }
  this.smokeSignal = function () {
    if (this.logStatus < this.message.length / 10){
      alert("Not enough fuel to send " +
             "the current message!);
    } else {
      this.lightFire();
      var x = this.message.length;
      for(var i = 0; i

Give all common methods that a "class" of objects will use to the constructor’s prototype.

function SignalFire( ID, startingLogs ){ 
  this.fireID = ID;

  this.logsLeft = startingLogs;
}

SignalFire.prototype = {
  this.addLogs = function ( numLogs ){
 
    this.logsLeft += numLogs;

  }
  this.lightFire = function () {
 
    alert("Whoooosh!");

  }
  this.smokeSignal = function () {
    if (this.logStatus < this.message.length / 10){
      alert("Not enough fuel to send " +
             "the current message!);
    } else {
      this.lightFire();
      var x = this.message.length;
      for(var i = 0; i

USE A DOCUMENT FRAGMENT TO INSERT ADDITIONS ALL AT ONCE:
Adding DOM elements individually ain't always speedy, since each new addition to the DOM causes document "reflow", which can really hinder user experience.

var list = document.getElementById("kotwList");
 
var kotw = ["Jenna Rangespike", 

            "Neric Farthing",
            "Darkin Stonefield"];
for (var i = 0, x = kotw.length; i

Note: Each time the list is appended, we access the DOM and cause an entire document reflow. Not as speedy as we’d like, especially if our list was huge...

Solution:
Use a document fragment to insert additions all at once. Fragments are invisible containers that hold multiple DOM elements without being a node itself.

var list = document.getElementById("kotwList");
 
var kotw = ["Jenna Rangespike", 

            "Neric Farthing",
            "Darkin Stonefield"];
var fragment = document.createDocumentFragment();
for (var i = 0, x = kotw.length; i

Note: Now we add each new li element to the staging fragment, instead of to the document itself. And append all of our new text nodes in one fell swoop, using only one DOM touch!

DECLARE VARIABLES AS FEW TIMES AS POSSIBLE
Every var keyword adds a look-up for the JavaScript parser that can be avoided with comma extensions. Commas used after an initial declaration can signal that you'll declare further variables.

Declaring in loops should thus be used with caution. Anticipate variable needs to avoid the processor burden of creating a new var over and over.

According to all these statements code transforms to:

var list = document.getElementById("kotwList"),
    kotw = ["Jenna Rangespike", 

            "Neric Farthing",
            "Darkin Stonefield"],
    fragment = document.createDocumentFragment(),
    element;
for (var i = 0, x = kotw.length; i

EFFICIENT CHOICES FOR STRING CONCATENATION
Different string building methods will yield different results in terms of execution speed.

The standard concatenation operator has been optimized in most modern browser versions, and is an ideal choice for a small number of string concatenations.

var turn = "";
turn += knight;
turn += action;
turn += weapon;

For concatenations over an array's contents, use the join() method inherited from the Array prototype.

var newPageBuild = [ "", "", "", "

",! ***a hundred or more other html elements***,! "", “", "" ]; page = newPageBuild.join("\n");

Note: The join method concatenates each index of the array, "joined" by any string parameter you pass in. In addition to being faster in tests than many String methods, it is also easier to read.

JavaScript Best Practicies : Syntax

Ternary Conditionals

isArthur && isKing ? 
    (weapon = "Excalibur", helmet = "Goosewhite") : 
        isArcher ? (weapon = "Longbow", helmet = "Mail Helm") : 
        (weapon = "Longsword", helmet = "Iron Helm");;

The “OR” Operator

  • When used in assignment, the OR operator will try to select the first value it encounters that is not “false”.
  • The OR operator takes the leftmost “truth” value, and if none exists, the last “false” value.
var result1 = undefined || 42;
console.log(result1); // 42

var result2 = 0 || ["Item1", "Item2"];
console.log(result2); // ["Item1", "Item2"]

var result3 = "" || {type: "Type", item: "Item"};
console.log(result3); // {type: "Type", item: "Item"}

When all elements are “true”, the FIRST “true” value assigned.

var result1 = "Value" || "Item";
console.log(result1); // "Value"

When all elements are “false”, the LAST “false” value assigned.

var result1 = undefined || "";
console.log(result1); // ""

The “AND” Operator

  • The && operator takes the rightmost “truth” value or the first “false” value.
var result1 = undefined && 42;
console.log(result1); // undefined

var result2 = 0 && ["Item1", "Item2"];
console.log(result2); // 0

var result3 = "" && {type: "Type", item: "Item"};
console.log(result3); // ""

When all elements are “true”, && will return the LAST “true” value found.

var result1 = "Value" && "Item";
console.log(result1); // "Item" 

The Switch Block

function Knight (name, regiment){
 
this.name = name;
 
this.regiment = regiment;
switch (regiment) {

  case 1:

    this.weapon = "Broadsword";
    break;

  case 2:

    this.weapon = "Claymore";
    break;

  case 3:

    this.weapon = "Longsword";
    break;
  case 5:

    this.weapon = "War Hammer";
    break;
  case 6:

    this.weapon = "Battle Axe";
    break;
  case 4:
 
  case 7:
 
  case 8:
    this.weapon = "Morning Star";
    break;
  case "King":"
    this.weapon = "Excalibur";
    break;
  default:
    alert(name + " has an incorrect " + "
        "regiment, Master Armourer!" + "
        "\n\nNo weapon assigned!");

A carefully organized switch block can add LEAST common properties first and MOST common, last.

function ceremonialDagger(knight, rank){
	this.length = 8;
	this.owner = knight;
	switch(rank){
	  case "King": this.diamonds = 1;
	  case "High Constable": this.amethyst = 2;
	  case "Field Marshal": this.sapphires = 4;
	  case "Captain": this.emeralds = 1;
	  case "Knight": this.rubies = 6;
  	}
}

var marshalsDagger = new ceremonialDagger("Timothy", "Field Marshal");
console.log(marshalsDagger); // ceremonialDagger {length: 8, owner: "Timothy", sapphires: 4, emeralds: 1, rubies: 6}

The Event-Driven Programming Model

In the old days, computer programs often ran in batch mode – they read in a batch of data, did some computation on that data, and then wrote out the results. Later, with time-sharing and text-based terminals, limited kinds of interactivity became possible – the program could ask the user for input, and the user could type in data. The computer could then process the data and display the results on screen.

Nowadays, with graphical displays and pointing devices like mice, the situation is different. Programs are generally event driven; they respond to asynchronous user input in the form of mouse-clicks and keystrokes in a way that depends on the position of the mouse pointer. A web browser is just such a graphical environment. An HTML document contains an embedded graphical user interface (GUI), so client-side JavaScript uses the event-driven programming model.

In client-side JavaScript, the web browser notifies programs of user input by generating events. There are various types of events, such as keystroke events, mouse motion events, and so on. When an event occurs, the web browser attempts to invoke an appropriate event handler function to respond to the event. Thus, to write dynamic, interactive client-side JavaScript programs, we must define appropriate event handlers and register them with the system, so that the browser can invoke them at appropriate times.

In event-driven programming, you write a number of independent (but mutually interacting) event handlers. You do not invoke these handlers directly, but allow the system to invoke them at the appropriate times. Since they are triggered by the user’s input, the handlers will be invoked at unpredictable, asynchronous times. Much of the time, your program is not running at all but merely sitting waiting for the system to invoke one of its event handlers.

Шаблоны проектирования

JavaScript, будучи динамическим нетипизированным языком, опирающимся на использование прототипов, иногда позволяет удивительно легко и даже тривиально реализовать шаблоны проектирования.

Continue reading

Основные приемы и шаблоны JavaScript

  • Снижение количества глобальных переменных, в идеале – не более одной на приложение.
  • Использование единственного объявления var в функциях, что позволяет одним взглядом охватить все переменные и предотвращает появление неожиданностей, вызванных особенностями механизма подъема переменных.
  • Циклы for (использовать только для массивов), циклы for-in (использовать только для объектов), инструкции switch, «eval() – это зло», нежелательность расширения прототипов.
  • Следование соглашениям по оформлению программного кода (последовательное использование пробелов и отступов; использование фигурных скобок и точек с запятой даже там, где они являются необязательными) и соглашениям по именованию (конструкторов, функций и переменных).

Необходимо стремиться свести к минимуму операции обращения к дереву DOM. Это означает, что:

  • Следует избегать обращений к элементам DOM внутри циклов
  • Желательно присваивать ссылки на элементы DOM локальным переменным и работать с этими переменными
  • Следует использовать интерфейс селекторов, где это возможно
  • Следует сохранять значение свойства length в локальной переменной при выполнении итераций через коллекции HTML

Стараться свести к минимуму количество операций, модифицирующих дерево DOM, что означает накапливать изменения, выполняя их за пределами «живого» дерева DOM документа.