JavaScript Tip: Remove ‘falsy’ Items Out of an Array

Posted in JavaScript

The new ECMAScript 5 brought a lot of enhancements that we used to see only on JavaScript frameworks. The Array class now has methods like forEach, map & filter, which are very useful.

If you need to support older browsers, which you probably do, this filtering method can be also found in MooTools (Array#filter), jQuery ($.grep) and other JS frameworks.

A quick tip to remove all falsy (false, null, undefined, 0, NaN or an empty string) items out of an array:

var a=[1,2,"b",0,{},"",NaN,3,undefined,null,5];
var b=a.filter(Boolean); // [1,2,"b",{},3,5]

Since Boolean constructor is also a function, it returns either true for ‘truthy’ argument or false for ‘falsy’ argument.

For example:

Boolean(0); // false
Boolean(true); // true
Boolean(1); // true
Boolean(""); // false
Boolean("false"); // true. "false" is a regular, non-empty string

And writing

b=a.filter(Boolean);

is actually the same as writing:

b=a.filter(function (x) { return Boolean(x); });

Links^2 – October 28th, 2010

Posted in Links

Asynchronous JavaScript Queue/Sequence

Posted in JavaScript

What are Asynchronous Functions?

An asynchronous function is a function whose completion depends on the actions of another object. The program in which it runs does not wait for the object to return a result, rather, that object “pushes” the result when it’s finished. This push comes through the callback function – a function defined specifically for the purpose of receiving a result, and that object calls the function with arguments it supplies. The signature of the callback function contains these arguments, and uses them in order to complete the procedure.

For example: asynchronous use of XMLHTTP. Upon sending the request to the server, the other scripts keep running while the page continues functioning. The XMLHTTP object has an event named onreadystatechange which is called each time the server returns an answer. This is unlike the synchronous case, where the browser waits for a response from the server. The window ‘freezes’ and only comes back to life when the response is received. This behavior is simply not Internet-correct, and not user-friendly.

Usually when we have an asynchronous function, we’d like another function to run upon its completion. We’ll put the call to the second function in the callback of the first one.

If we have a large number of functions and callback, they start to depend on each other: when A terminates call B, when B terminates call C, and so on. If I pull B out of the sequence, I’ve broken the chain, because C will not be called.

Case of Asynchronous Functions in Sequence

As an example, we’ll look at this sequence:

  1. Performing a semi-transparency effect on an element to be displayed, and once complete:
  2. A button appears in the element, when clicked:
  3. An XMLHTTP request is sent to the server, and when a response is received:
  4. A message is displayed, alerting that the process has finished.

The division into functions is quite simple:

function effectElement() {
	var div=document.getElementById("div");
	var opacity=0;
	var iv=setInterval(function () {
		opacity+=.05;
		div.style.opacity=opacity;
		if (opacity>=1) {
			clearTimeout(iv);
			showButton();
		}
	},50);
}
function showButton() {
	var button=document.getElementById("button");
	button.style.display="";
	button.addEventListener("click",function () {
		requestServer();
	},false);
}
function requestServer() {
	var xh=new XMLHttpRequest();
	xh.open("GET","url.htm",true); // true - async call
	xh.onreadystatechange=function () {
		if (xh.readyState==4) {
			div.innerHTML=xh.responseText;
			finish();
		}
	};
	xh.send(null);
}
function finish() {
	alert("finish");
}
window.addEventListener("load",function () {
	effectElement();
},false);

We see here that we can call the next function within each function’s callback. But what would happen if we were to remove one of the functions from the sequence? We’d have to change the function containing the call to the removed function, to call another function. And what would happen if we wanted to change the order? A mess.

Generic Solution for a Sequence of Asynchronous Functions

I’ve tried to think of a generic solution to the problem, a solution which would let me decide which function comes after which with minimum code and maximum flexibility, and where each function calls the next without being dependent on it.

This is the basic syntax:

var sequence=new Devign.Sequence();
sequence.add(effectElement);
sequence.add(showButton);
sequence.add(requestServer);
sequence.add(finish);
sequence.start();

Within each callback, the current sequence should be advanced by:

currSequence.next();

where currSequence is passed with the function as a single argument.

Simple, isn’t it?

We can play with the order of the functions, add and remove as much as we want.

Devign.Sequence Class

// Devign.Sequence class
if (typeof(Devign)=="undefined") var Devign={};
Devign.Sequence=function () {
	// private fields
	this.list=[]; // a list of functions
	this.index=-1;
	this.aborted=false;
	// public fields
	this.finished=false;
};
// public methods
Devign.Sequence.prototype={
	// adds a new function
	add:function (sequenceFunction) {
		this.list.push(sequenceFunction);
	},
	// starts the sequence from the first function
	// fires 'onStart' if exists
	start:function () {
		this.index=-1;
		this.aborted=false;
		this.next();
		if (typeof(this.onStart)=="function") this.onStart();
	},
	// ends the sequence
	// fires 'onEnd' if exists
	end:function () {
		if (typeof(this.onEnd)=="function") this.onEnd();
		this.finished=true;
	},
	// proceeds the sequence
	// if the sequence has finished calls 'end'
	next:function () {
		// if sequence was aborted - ignore next statements
		if (this.aborted) return;
		this.index++;
		if (this.index==this.list.length) return this.end();
		var currFunction=this.list[this.index];
		// calls the function with the sequence as an argument
		if (currFunction) currFunction(this);
	},
	// aborts the sequence by setting the index to 'not started' and the flag aborted to true
	abort:function () {
		this.index=-1;
		this.aborted=true;
	}
};

Each instance of the class has an array of functions, to which we can add more functions with the method add. Furthermore, there is numerical field named index which tracks the index of the function currently being executed (with -1 meaning the sequence has not yet begun).
For each instance we can also define two events: onStart and onEnd. If defined, they will run at the appropriate time.
Each time we move forward in the sequence, the index is incremented and the next function is called from the array. The function is called with the parameter this which refers to the instance of the class. The reference to the class is sent so that it may be identified from within the function, and advanced with next.

Complete Code

<script type="text/javascript" src="Devign.Sequence.js"></script>
<script type="text/javascript">
var sequence=new Devign.Sequence();
sequence.add(effectElement);
sequence.add(showButton);
sequence.add(requestServer);
sequence.add(finish);
window.addEventListener("load",function () {
    sequence.start();
},false);
function effectElement(currSequence) {
    var div=document.getElementById("div");
    var opacity=0;
    var iv=setInterval(function () {
        opacity+=.05;
        div.style.opacity=opacity;
        if (opacity>=1) {
            clearTimeout(iv);
            currSequence.next();
        }
    },50);
}
function showButton(currSequence) {
    var button=document.getElementById("button");
    button.style.display="";
    button.addEventListener("click",function (e) {
        currSequence.next();
        button.disabled=true;
        button.value="Wait...";
        e.preventDefault();
    },false);
}
function requestServer(currSequence) {
    var div=document.getElementById("div");
    var xh=new XMLHttpRequest();
    xh.open("POST","/ajax_html_echo/",true); // true – async call
    xh.onreadystatechange=function () {
        if (xh.readyState==4) {
            div.innerHTML=xh.responseText;
            currSequence.next();
        }
    };
    xh.send("html=Ajax completed");
}
function finish(currSequence) {
    alert("finish");
    currSequence.next();
}​
</script>
<div id="div" style="opacity:0;height:100px;width:100px;border:1px solid #000;background-color:#32C3D7;">
	<input type="button" id="button" value="Click" style="display:none"/>
</div>

Links^2 – October 5th, 2010

Posted in Links

MooTools toElement Method and ToElement Mixin

Posted in MooTools

The toElement Method

Classes like Calendar, Slider, AutoCompleter etc. are all containing elements or responsible for elements.

There are several approaches for how to handle the element in the class:

  • Pass a container element as an argument to the constructor of the class, and append to it new elements that the class creates
  • Have the actual behavior-less element(s) on the HTML and pass them to the class constructor as an argument, the class will apply its behaviors on them
  • Create all elements in the class and have them available for appending

Each approach is good for a different situation, but the toElement method is meant mostly for the last one.

Example of a plain class, and how its element is being appended to the document:

var AutoCompleter=new Class({
	initialize:function () {
		this.input=new Element("input");
		// autocomplete magic
	}
});
var autoCompleter=new AutoCompleter();
$("container").grab(autoCompleter.input);

This is quite ugly to use the public property input, which its name can be changed someday and then the code breaks. Moreover, in this way, each class declares its own property and this can lead to inconsistency between the property names.

This is where the toElement method comes in handy: it’s a MooTools convention for a method that simply returns the element.

var AutoCompleter=new Class({
	initialize:function () {
		this.input=new Element("input");
		// autocomplete magic
	},
	toElement:function () {
		return this.input;
	}
});
var autoCompleter=new AutoCompleter();
$("container").grab(autoCompleter.toElement());

But wait, there’s more: MooTools $ / document.id function knows that if it gets an object that has the toElement method, the method should be invoked and the returned element will be returned out of the document.id function. Luckily, all of the MooTools Element methods use document.id inside them, so, for instance, when grab or adopt are called with any object as an argument, it will be passed thru the document.id function which will translate it to the toElement result. Hence, we can use this:

$("container").grab(autoCompleter);

The ToElement Mixin

The ToElement Mixin is supposed to make the toElement method even simpler, and make it lazy-load the element, i.e. create it only when needed.

var ToElement=new Class({
	ui:{},
	toElement$ensureElement:function () {
		var element=this.toElement$getElement();
		if (!element && this.build) this.build();
	},
	toElement$getElement:function () {
		return (this.ui ? this.ui.element : this.element) || this.element;
	},
	toElement:function () {
		this.toElement$ensureElement();
		return this.toElement$getElement();
	}
});

Usage:

var AutoCompleter=new Class({
	Implements:[ToElement],
	initialize:function () {
	},
	build:function () {
		this.ui.element=new Element("input");
		// autocomplete magic
	}
});
var autoCompleter=new AutoCompleter();
// element isn't ready yet
// the grab calls document.id which calls toElement, where the element is prepared
$("container").grab(autoCompleter);

First, it adds a ui hash to every class instance. That’s my convention to save elements in classes of this kind. Second, it adds a toElement method, which is responsible of calling the build method if exists, and return this.ui.element or this.element out of the instance.

Benefits are:

  • Lazy load the element – it’ll be created only when the document asks for it
  • ui hash to contain all other elements, and a build method as a simple convention



Page optimized by WP Minify WordPress Plugin