HTML5 local storage 1-2-3

1:21 PM Xun 0 Comments

A lot of excitement about HTML5 tends to be about the infinite multimedia can-dos, videos, audios and canvas combined with ever-more powerful JavaScript, but localstorage is also one of the cool things about HTML5, without which a lot of games probably will be slow to a crawl.

LocalStorage is much like a cookie, in that they are both sweet and energy-packed. A cookie is limited in size, 4kb; while most browsers can have a local storage as big as 4mb. Also cookies are sent back and forth with every request for javascript files, images, ajax data calls, this adds a lot of unnessary bandwidth.




Browser side localstorage has two forms:
sessionStorage
and
localStorage
. They are essentially the same, other than that
sessionStorage
resets itself when a session restarts, while
localStorage
persists across browsers restarts.

It is easy to set, remove and retrieve localstorage key-value pairs.


var cacheKey = "demoData" + Id;

//set
localStorage.setItem(cacheKey, demoData);

//get
var demoData = localStorage.getItem(cacheKey);

//remove
localStorage.removeItem(cachekey);

You can also manage your localstorage through chrome's developer tool.




One big catch,
localstorage
stores everything as a string, so if you want to store an object, say for example, a JSON object, most likely you will get something useless like "[object object]". To circumvent this, you need to string-fy your object first, then store it, then parse it back into object when you are ready to use it. As in the following:


// a function to store JSON data returned from AJAX
var saveData = function (data) {
//parse the string data back to JSON object
var strdata = JSON.stringify(data)
localStorage.setItem(cacheKey, strdata);
var value = localStorage.getItem(cacheKey);
//parse the string data back to JSON object
dosomething(JSON.parse(value));
};


And the following is a snippet of code that checks for if local storage with certain key exists, if yes, operate on it; if no, ajax it, then store it.


var GetData = function (id) {

cacheKey = "demo_" + id;

var value = localStorage.getItem(cacheKey);
if (value) {
doSomething(JSON.parse(value));
}
else {
common.Ajax(ajaxUrl, saveData, onError);
}
}


Since it is possible for us to go offline sometimes, it is quite possible we make changes to localstorage offline. And it would be upsetting if we would loose that information when online. So there is some techniques to sync the offline data with server.

The following is some code stolen from http://hacks.mozilla.org/2010/01/offline-web-applications/, that does the following:


1. If you set your status and you’re online, it sends the status.
2. If you set your status and you’re offline, it stores your status.
3. If you go online and have a stored status, it sends the stored status.
4. If you load the page, are online, and have a stored status, it sends the stored status.



function whatIsYourCurrentStatus() {
var status = window.prompt("What is your current status?");
if (!status) return;
if (navigator.onLine) {
sendToServer(status);
} else {
saveStatusLocally(status);
}
}

function sendLocalStatus() {
var status = readStatus();
if (status) {
sendToServer(status);
window.localStorage.removeItem("status");
}
}


window.addEventListener("load", function() {
if (navigator.onLine) {
sendLocalStatus();
}
}, true);

window.addEventListener("online", function() {
sendLocalStatus();
}, true);

window.addEventListener("offline", function() {
alert("You're now offline. If you update your status, it will be sent when you go back online");
}, true);


Nowadays, it is hard to find any pure DIY (do-it-yourself) javascript, everyone relies on one or multiple JavaScript libraries. For localstorage management, we have DSt. DSt is "simple, lightweight JavaScript library for using HTML5 DOM stroage".


jStorage is another one.

"jStorage is a simple wrapper plugin for Prototype, MooTools and jQuery to cache data (string, numbers, objects, even XML nodes) on browser side. Note that functions, DOM nodes, host objects and such can not be saved.".

0 comments:

JavaScript: Anonymous functions

1:21 PM Xun 4 Comments

JavaScript can definitely look weird and convoluted, even in those code people say are just about "relatively simple concepts" and "are applied in practice quite often". For example, this little JavaScript quiz. And cherry pick one example:

 var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();
})(foo.bar);


It sure looks weird and convoluted to me.

About half of the weird-ness about JavaScript has to do with anonymous function, the way it is created, called, passed with parameters, passed around. That said, anonymous function is definitely ubiquitous and indeed worthy of some true understanding.

Anonymous function by definition is simple. It is just a function without name (in contrast to a non-anonymous function that has a name).

Example of a non-anonymous function:

 function sayHello(){
alert("hi");
}


Example of a anonymous function:

 var sayHello = function(){
alert("hi");
};


What's the difference between the two
sayHellos
? Logically they are the same. However, the second one is an expression, an anonymous function assigned to a variable
sayHello
; The first one is a function declaration, while the second one a function expression. This causes the difference how they can be accessed.

Example of different accessibility between anonymous function and non-anonymous function:

 
// anonymous function assigned to a variable cannot be called before the variable is initialized
fnAnonymous(); // undefined

var fnAnonymous = function(){
alert("hi");
};

fnAnonymous(); //hi

// a named function can be accessed anywhere as long as it is within the same scope that the function is created
fnNamed(); // hi

function fnNamed(){
alert("hi");
};

fnNamed(); //hi

So even the above
fnAnonymous()
are
fnNamed()
are essentially the same, yet one (
fnNamed
) is created through function declaration, the other through function expression. The former (named function) is created in the scope before execution and can be assessed throughout in the same scope, while the later is created until the expression is evaluated and cannot be assessed before the line of evaluation.

Anonymous functions are created all the time, accidentally or not. They exist in different shapes and forms.

All the following involves anonymous functions:

 // function expression
var sayHello = function (){
alert("hi");
};

// in an object
var Person = {
sayHello: function(){
alert("hi");
}
};

// event handler
$("p").click = function(){
alert("hello");
};

// ajax callback from http://api.jquery.com/jQuery.ajax/
$.ajax({
url: "test.html",
context: document.body,
success: function(){
$(this).addClass("done");
}
});

//Self-evoking anonymous functions
((function () {
alert("hi");
})());


What are anonymous functions for? Benefits?

Simply, anonymous functions are used for the reasons of: a) code brevity. It often makes sense to use anonymous functions calls in callbacks and event handlers; b) scope management. Anonymous functions can be used to create temporary/private scope; c) Anonymous function are often handy in closures and recursions.

In JavaScript, scope could be tricky but it is fundamental to JavaScript understanding. And anonymous functions are often used to create a temporary / private scope.

A commonly cited example is jQuery.

 (function( window, undefined ) {

var jQuery = (function() {
});

// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;

//
})(window);


The above ensures the function is called immediately; it also ensures every variable declared in the anonymous function is a private variable, therefore won't spill into and pollute the global scope, which is extremely important from a library's perspective; it also ensures that the scope chain is destroyed after the function finishes execution.


Recursions


Recursions are functions that call themselves, they are often used to solve problems such as factorials, the tower of hanoi, golden ratio (See wiki Recursion. Or, fibonacci numbers.

 function fibonacci(n) {
if (n < 2)
return n;

return fibonacci(n - 1) + fibonacci(n - 2);
}

alert(fibonacci(6)); //8


It works fine. But it can/should be improved with two things:
arguments.callee
and function memorization. As the following:

 function f(n) {

if (n < 2)
return n;

if (f.answers[n] != null)
return f.answers[n];

f.answers[n] = arguments.callee(n - 1) + arguments.callee(n - 2);

return f.answers[n];
}

f.answers ={};

var fibo = f;
alert(fibo(10)); //55
alert(fibo(11)); //89



So, first,
arguments.callee
. All functions have a pointer
arguments.callee
to itself. Using
arguments.callee
instead of the function names ensures that the function can always be accessed, even when the function is assigned to a variable; second, store the computed value in memory. Because all recursions involves doing the same calculation over and over again, we can just save some extra work and repetitions by storing the known/already computed answers.


Closures

Functions returned from another function are called closures. Closures and anonymous functions often goes hand in hand.

 $('#foo').click( function() {
alert('User clicked on "foo."');
});


Closures can often get into trouble with loops, and one sure way to get out of the loop is to use anonymous function to create a temporary scope.

So a loop like this is problematic.

 for (var i = 1; i <= 10; i++) {
$('#Div' + i).click(function () {
alert('#Div' + i + " is kicked");
return false;
});
}


Yet if you rewrite it a bit, it will work!

 for (var i = 1; i <= 10; i++) {
(function(v){
$('#Div' + v).click(function () {
alert('Div' + v + " is kicked");
return false;
})
})(i);
}


Read more about closures at JavaScript closures


Back to the weird anonymous function

Now let's go back to the weird code that sits squarely in the quiz we mentioned in the beginning.

 var foo = {
bar: function() { return this.baz; },
baz: 1
};

(function(){
return typeof arguments[0]();
})(foo.bar);



What would be the correct answer?
a) "undefined"
b) "object"
c) "number"
d) "function"

The answer is a) "undefined". I did not get this right until I ran the code. I cheated.

Brief explanation (found in the comments section):

"It’s important to understand that this is not a closure variable. Instead, it is determined at function-run-time, by the entity which it ‘belongs to’ at the time — and if there is no such object, then the object is window. So if you call foo.bar(), then this will point at foo. But when you call arguments[0](), it points at arguments instead. Since arguments.baz is undefined, you get this particular behaviour."

hmm. Takes some chewing.

A hasty conclusion

Well, there is still so much more about JavaScript anonymous function. And it could be a pain. If it is, hopefully this would alleviate your pain a bit.

So long!


Source:

Secrets of the JavaScript Ninja
Professional JavaScript for Web Developers
Javascript quiz
JavaScript closures

4 comments:

JavaScript Closures

11:02 AM Xun 1 Comments

A lot has been said about and done with JavaSript closures. From the much technical and inner-mechanism oriented (and much recommended) article: Javascript Closures, to the highly accessible and simplified explanation at JavaScript Closures for Dummies, there is also very good run-down of use-cases at Use Cases for JavaScript Closures.

That JavaScript could have closure is because functions in JavaScript can be anywhere and anything, functions can be anonymous, self-evoking; functions can be passed as parameters, and returned as values. And when a function is returned from inside of another function, it has access to the variables in its parent scope. Thus it is said, that the function closes over / binds / remembers the environment from which it was created.


function HelloWorldClosure(){
var counter = 0;

var hello = function(){
counter += 1;
alert( "Hello World " + counter);
}

return hello;
}

var hello1 = HelloWorldClosure();
var hello2 = HelloWorldClosure();


So in the above, two closures are formed when two variables
hello1
and
hello2
are assigned to returned value of
HelloWorldClosure
. Now, we can call
hello1()
,
hello2()
as we would with any functions. Each call would increment the counter variable independently.

hello1();  // 1
hello1(); //2

hello2(); //1
hello2(); //2

hello1(); //3


Closures can be easily confused with regular inner functions. For example:

function HelloWorld(){
var counter = 0;

function (){
counter += 1;
alert( "Hello World " + counter);
}

hello();
}

HelloWorld();


When the outer function
HelloWorld
is called, it will simply create and initiate a new varible counter, then go through the chain of function calls, and execute
hello()
, and exit.


Multiple closures

Multiple closures can live inside one big outer functions, therefore share the environment. This can have unintended consequences.

For example:

function HelloWorldClosure(){
var counter = 0;

var hello = function (){
counter += 1;
alert( "Hello World " + counter);
}

var byebye = function(){
counter -= 1;
alert("bye " + counter);
}
return {hi: hello, bye:byebye};
}

var hello3 = HelloWorld();
hello3.hi(); //1
hello3.hi(); //2
hello3.bye(); //1


Why because hello and bye both are closures that have equal rights to the variable living in the parent function
HelloWorld
.


setTimeOut
and
setTimeInterval


SetTimeOut and SetTimeInterval take two parameters: 1) a function or a reference to a function as its first parameter; 2) the number of milliseconds to wait before excuting the code. The function passed to
setTimeout
/
setTimeInterval
is a closure, it has control over the variable in the environment.

        var counter = 0;

var incrementPerSec = function () {
console.log(counter);
counter = counter + 1;
};

setInterval(incrementPerSec, 1000);



Closures often means functions are stored and executed later. A inner function that is returned from an outer function does not get executed the outer function is called, it is only executed when the function itself is called. Therefore in the above example,

var hello3 = HelloWorld();
hello3.hi(); //1


Also in the
setTimeInterval
function, the function is stored and only executed after a set time.

Because of this delayed execution, closures can often get tangled with loops.

   for (var i = 0; i < 10; i++) {
setInterval(function () {
console.log(i);
}, 1000);
}



The above function will log a 10 (nothing but 10) every second. Because by the time the little function starts to log the i value, i has already finished its iteration cycle and stays put at value 10.

So how do you log the i value in a loop in a delayed fashion? One solution could be using a function that execute immediately to capture the i value.

  for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () { console.log(i); }, 1000);
})(i);

}



So the above uses an self-evoking anonymous function in the form of
(function(){})()
. Turned out that it is frequently used to form a closure.


Closures everywhere

Once you noticed closures, you noticed them everywhere. For example, jQuery.

The first thing you notice about jQuery, in fact, a lot of libraries, is that it uses an anonymous function as the library wrapper.


(function() {
var jQuery = window.jQuery = function () {
//
};
// ...
};
}();



The anonymous function ensure the library, all of its variables and functions, is completely enclosed in its own environment.


jQuery
$(document).ready()


In jQuery, all calls are started inside the
$(document).ready
function. So by definition, all function calls are inner functions. And quite of the inner functions are closures. For example, the event binding functions in jQuery are all closures.

Take for example, the hover event.

//http://code.jquery.com/jquery.js
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}


and we use the hover function as such.

//http://api.jquery.com/hover/
$("li").hover(
function () {
$(this).append($(" ***"));
},
function () {
$(this).find("span:last").remove();
}
);



Not surprisingly, closures sometimes can collide over the variables in the environment.

                                                                  






Minus one: My value now is 10

Plus one: My value now is 10





AJAX Callbacks


AJAX callbacks uses closures to manipulate data outside of its scope.

$('#letter-b').click(function () {
var txtDiv = $("#bText").html("loading...");
$.ajax({
url: "data.html",
success: function (data) {
txtDiv.append(data);
}
});
return false;
});



JavaScript private and public members


Closure is what makes differenticated access control in JavaScript possible, that is, that is why JavaScript get to have "peudo-class" (objects) with private and public members.

The following uses the widely popular YUI module pattern.

YUI module pattern

 var Person = function(age, name){

var _age = age;
var _name = name;

return{
function getName(){
return _name;
}

function setName(){
_name = name;
}
}
}


The YUI module pattern is also rewritten as the following for the purposes of a) public and private members have the same coding style; b) the return section is less bloated and easier to read.

 var Person = function(age, name){

var _age = age;
var _name = name;
var getName = function(){
return _name;
}
var setName = function(){
_name = name;
}

return{
getName: getName,
setName: setName
}
}



Both use closures to seperate public from private members. From outside, only name can be get and set through privided methods:
getName
,
setName
.


var perter = new Person("peter", 30);

peter.setName("Person Johnson");

console.log(peter.getName()); // return "Person Johnson"

var mary = new Person("mary", 30);

//mary.setName("Person Johnson");

console.log(mary.getName()); // return "Person Johnson"



Source:

Javascript Closures
Use Cases for JavaScript Closures
JavaScript Closures for Dummies
JavaScript Closures for Dummies
Learning JQuery: Appendix: Closures
Learning JQuery: Appendix: Closures
Secrets of the JavaScript Ninja

1 comments: