JavaScript | Dmytro Shteflyuk's Home https://kpumuk.info In my blog I'll try to describe about interesting technologies, my discovery in IT and some useful things about programming. Tue, 08 Sep 2015 00:40:32 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 Do I need to buy additional memory? https://kpumuk.info/javascript/do-i-need-to-buy-additional-memory/ https://kpumuk.info/javascript/do-i-need-to-buy-additional-memory/#comments Tue, 29 May 2007 14:07:41 +0000 http://kpumuk.info/life/do-i-need-to-buy-additional-memory/ Today I spent almost full day for reflection on to buy or not additional memory for my computer. As a result new script was born, and he saved my brain: If you have questions like this — ask the script, maybe it would help you too :-)

The post Do I need to buy additional memory? first appeared on Dmytro Shteflyuk's Home.]]>
Today I spent almost full day for reflection on to buy or not additional memory for my computer. As a result new script was born, and he saved my brain:

Do I need to buy additional memory?

If you have questions like this — ask the script, maybe it would help you too :-)

The post Do I need to buy additional memory? first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/javascript/do-i-need-to-buy-additional-memory/feed/ 28
JavaScript optimization Part 3: Attaching events https://kpumuk.info/javascript/javascript-optimization-part-3-attaching-events/ https://kpumuk.info/javascript/javascript-optimization-part-3-attaching-events/#comments Wed, 09 May 2007 23:41:55 +0000 http://kpumuk.info/javascript/javascript-optimization-part-3-attaching-events/ This is a third part of the JavaScript optimization tutorial, and today I’m going to talk about events. Sorry for a long delay between posts, I hope remaining parts would not be delayed so much. Scenario: you have some elements and you need to add some actions to them (for example, when user moves mouse […]

The post JavaScript optimization Part 3: Attaching events first appeared on Dmytro Shteflyuk's Home.]]>
This is a third part of the JavaScript optimization tutorial, and today I’m going to talk about events. Sorry for a long delay between posts, I hope remaining parts would not be delayed so much.

Scenario: you have some elements and you need to add some actions to them (for example, when user moves mouse cursor over element, or clicks on elements).

This is pretty usual task in web-development. And the first thing that everybody knows is a different event attaching syntax in Internet Explorer and Firefox: first uses element.attachEvent, second — element.addEventListeners. Therefor you need to add code, which would detect what browser is being used and what method to use in each case. In the most popular client script library Prototype it is already standardized and you can always use Event.observe. Let’s benchmark a little.

I’m going to start attaching events from manual detection of which browser is being used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Attaching events
for (var i = items.length; i--; ) {
    if (items[i].addEventListener) {
        items[i].addEventListener('click', e_onclick, false);
    } else if (items[i].attachEvent) {
        items[i].attachEvent('onclick', e_onclick);
    }
}
// Detaching events
for (var i = items.length; i--; ) {
    if (items[i].removeEventListener) {
        items[i].removeEventListener('click', e_onclick, false);
    } else if (items[i].detachEvent) {
        items[i].detachEvent('onclick', e_onclick);
    }
}

This approach shown best times: 188 and 203 ms in Internet Explorer 6 and 7, 125 and 141 ms in Firefox 1.5 and 2.0, and 63 ms in Opera 9, but there is one problem with it — memory leaks: Internet Explorer usually forget to clean up memory, used by event listeners, when you navigating to another page. Therefor all JavaScript frameworks which implement event attaching/detaching functions, provide functionality for removing listeners when you navigating to another page. Let’s test them.

Code for testing Prototype library:

1
2
3
4
5
6
7
8
// Attaching events
for (var i = items.length; i--; ) {
    Event.observe(items[i], 'click', e_onclick, false);
}
// Detaching events
for (var i = items.length; i--; ) {
    Event.stopObserving(items[i], 'click', e_onclick, false);
}

This is very slow, 6453 ms in Internet Explorer 6 and looks like some memory leaks are still exists (it became slower and slower with the lapse of time) and 365 — 653 ms in other browsers.

There are tons of problems and solutions with adding events (just look at the Advanced event registration models). Some time ago even PPK’s addEvent() Recoding Contest was over (but do not use the winner’s solution because of it’s inefficiency and memory leaks).

Instead of winner’s solution, I decided to test incredible and impertinent solution from Dean Edwards, which even does not use the addeventListener/attachEvent methods, but it is entirely cross-browser!

Used code:

1
2
3
4
5
6
7
8
// Attaching events
for (var i = items.length; i--; ) {
    addEvent(items[i], 'click', e_onclick);
}
// Detaching events
for (var i = items.length; i--; ) {
    removeEvent(items[i], 'click', e_onclick);
}

Results are as much impressive as when we used manual events attaching, and this approach is extremely fast to use it in real-world applications. Of course, you would say: “Stop, what you are talking about? I don’t want to use additional methods while Prototype is already used in my code!” Calm down, you don’t need to do it, just download Low Pro library (current version is 0.4, stay tuned). Ruby on Rails developers could use UJS Rails Plugin in their applications to improve performance — it uses Low Pro inside.

No Method IE 6 IE 7 FF 1.5 FF 2.0 Opera 9
1 manually 203 188 125 141 63
2 prototype.js 6453 653 547 469 365
3 addEvent 783 344 94 141 62

Benchmark: Attaching events

You can review benchmark and get your own results here.

Conclusions

  • Always use Low Pro along with Prototype.js (of course, if your application uses rich client logic).
  • Use manual events attaching when you need to get as much as possible speed from your application (for example, when you handling hundreds of elements). But don't forget about memory leaks!
  • Avoid events attaching whenever it's possible (for example, use :hover CSS selector instead of onmouseover event).
  • Keep your eyes opened, maybe tomorrow somebody would post another great performance optimization tip.

Links to other parts

The post JavaScript optimization Part 3: Attaching events first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/javascript/javascript-optimization-part-3-attaching-events/feed/ 10
JavaScript optimization Part 2: Applying styles to elements https://kpumuk.info/javascript/javascript-optimization-part-2-applying-styles-to-elements/ https://kpumuk.info/javascript/javascript-optimization-part-2-applying-styles-to-elements/#comments Tue, 27 Mar 2007 20:02:41 +0000 http://kpumuk.info/javascript/javascript-optimization-part-2-applying-styles-to-elements/ This is second part of articles cycle devoted to JavaScript optimization. In this post I’ll cover dynamic elements styling and explore a little HTML-rendering process. Also you will find here some tricks on how to make your applications faster. Scenario: you have elements in your document and you need to change their color, background, or […]

The post JavaScript optimization Part 2: Applying styles to elements first appeared on Dmytro Shteflyuk's Home.]]>
This is second part of articles cycle devoted to JavaScript optimization. In this post I’ll cover dynamic elements styling and explore a little HTML-rendering process. Also you will find here some tricks on how to make your applications faster.

Scenario: you have elements in your document and you need to change their color, background, or something else related to theirs style. For example, highlight table rows on mouse over or mark them when corresponding checkbox is checked.

And again I know two ways: using styles or set foreground(or background) color directly from JavaScript. Let’s test them before discussion:

1
2
3
4
var items = el.getElementsByTagName('li');
for (var i = 0; i < 1000; i++) {
    items[i].className = 'selected';
}

The average result is 187 – 291 ms, for the InternetExplorer 6 it is 512 ms, and in Opera 9 it is 47 ms.

1
2
3
4
5
var items = el.getElementsByTagName('li');
for (var i = 0; i < 1000; i++) {
    items[i].style.backgroundColor = '#007f00';
    items[i].style.color = '#ff0000';
}

I got results starting from 282 ms in Opera and ending with 1709 ms in Internet Explorer 6.

Result are clean and easy to understand:

No Method IE 6 IE 7 FF 1.5 FF 2.0 Opera 9
1 element.className 512 187 291 203 47
2 element.style.color 1709 422 725 547 282

Benchmark: Applying styles to elements

You can view benchmark test and get your own results here.

Looks like this is simplest optimization tip, but... there is one issue with Internet Explorer -- page update. Are you remember scenario described in the beginning of chapter, about onmouseover? When you change element's class name, your code is much faster, but the page would not be updated immediately. Look at this example. Try to click "Generate elements" when "element.className" radio button is selected. Then move your mouse pointer over the items, scroll list to the bottom, move mouse again (for slow machines items number would be less than default, for fast ones - greater). Have you noticed, that background changes not so fast as the mouse pointer moves? Now switch selected radio button to "element.style.color". Background changing smoothly, right?

At the bottom of page you see the number of onmouseover events triggered and average time spent to dispatch them. As you noticed, first radio button works two times faster! Why it looks slower? I think it is because when you changed className property Internet Explorer isn't actually updates UI, but placed event in update queue. If you have other ideas, please post comments.

Anybody, who read article up to this place, would probably say: "Hey, guy, you are cheating. Where is the :hover?". I'm hurry up to fix this shortcoming and describing this case right now. First, this thing is not working in the Internet Explorer 6 (and don't ask me "who need it?"). But this is not most difficult problem, performance of this issue is much worse. Even don't want to comment it, just select third radiobutton on previously given page and move your mouse in Internet Explorer 7 and Opera 9 (Firefox works great).

Conclusions

  • Use className when it's possible. It grants you more flexibility and control over site look.
  • If you have many items in your container element, and you need really fast UI, set styles directly through element's style property.

Links to other parts

  • Part 1: Adding DOM elements to document
  • Part 2: Applying styles to elements
  • Part 3: Attaching events
  • Part 4: Multiple anonymous functions (will be published soon)
  • Part 5: Attaching events on demand (will be published soon)
  • Part 6: Element hide and show (will be published soon)
  • Part 7: Elements collection enumeration (will be published soon)
The post JavaScript optimization Part 2: Applying styles to elements first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/javascript/javascript-optimization-part-2-applying-styles-to-elements/feed/ 4
JavaScript optimization Part 1: Adding DOM elements to document https://kpumuk.info/javascript/javascript-optimization-part-1-adding-dom-elements-to-document/ https://kpumuk.info/javascript/javascript-optimization-part-1-adding-dom-elements-to-document/#comments Sun, 25 Mar 2007 01:40:49 +0000 http://kpumuk.info/javascript/javascript-optimization-part-1-adding-dom-elements-to-document/ Most web-developers writing tons of JavaScript, especially in our Web 2.0 century. It’s powerful technology, but most browsers has very slow implementation of engine, and everyone at some instant decide to review code and make it faster. In this post I’ll share my experience and explain several tricks how to make your JavaScript as fast […]

The post JavaScript optimization Part 1: Adding DOM elements to document first appeared on Dmytro Shteflyuk's Home.]]>
Most web-developers writing tons of JavaScript, especially in our Web 2.0 century. It’s powerful technology, but most browsers has very slow implementation of engine, and everyone at some instant decide to review code and make it faster. In this post I’ll share my experience and explain several tricks how to make your JavaScript as fast as possible.

This is first article in 7 parts tutorial, stay tuned.

Scenario: you’re developing rich Internet application and you need to load dynamic elements using AJAX and then add them to current document. For some reason you don’t want (or can’t) use fully generated HTML, and decided to fetch items in JavaScript array.

I know two classic ways to do so: create elements using document.createElement() method and concatenate HTML string and assign it to parentElement.innerHTML property. Of course, you can combine both ways. Let’s examine this ways in details.

Classic way (and in ideal world the best way) is to use DOM for element manipulations:

1
2
3
4
5
for (var i = 1; i <= 1000; i++) {
    var li = document.createElement('li')
    li.appendChild(document.createTextNode('Element ' + i));
    el.appendChild(li);
}

Not so bad performance. Internet Explorer 6 is slowest – 1403 ms (but it is a slower browser in the world, right?), and other browser displayed results quickly (63 – 328 ms). Ok, but what about creating DOM element from HTML code?

1
2
3
4
for (var i = 1; i <= 1000; i++) {
    var li = document.createElement('<li>Element ' + i + '</li>');
    el.appendChild(li);
}

It works better in Internet Explorer 6 (1134 ms), but does not work in other browsers at all. Weird! Of course, you can add try/catch block and create elements using first approach in catch block for the other browsers. But I have better solution.

Every DOM node has attribute innerHTML which holds all child nodes as HTML string.

1
2
3
4
el.innerHTML = '';
for (var i = 1; i <= 1000; i++) {
    el.innerHTML += '<li>Element ' + i + '</li>';
}

Wow, I’m highly impressed how slow could be adding elements procedure (11391 – 307938 ms)! Cool result, right? It’s because browser tried to render list while we updating and it’s take so long time. Little optimization:

1
2
3
4
5
var html = '';
for (var i = 1; i <= 1000; i++) {
    html += '<li>Element ' + i + '</li>';
}
el.innerHTML = html;

All browsers shows great perfomance (31 – 109 ms), but Internet Explorer is still slow – 10994 ms. I found solution which works very fast in all browsers: to create array of HTML chunks, and the join them using empty string:

1
2
3
4
5
6
7
var html = [];
for (var i = 1; i <= 1000; i++) {
    html.push('<li>Element ');
    html.push(i);
    html.push('</li>');
}
el.innerHTML = html.join('');

It’s fastest approach for Internet Explorer 6 – 400 ms, and very fast in other browsers. Why I’m not saying fastest in case of Firefox? I added another test to make in cleaner:

1
2
3
4
5
6
7
var html = '';
for (var i = 1; i <= 1000; i++) {
    html += '<li style="padding-left: ' + (i % 50) +
    '" id="item-' + i + '">Element ' + i + ' Column ' +
    (i % 50) + '</li>';
}
el.innerHTML = html;

And second example:

1
2
3
4
5
6
7
8
9
10
11
12
13
var html = [];
for (var i = 1; i <= 1000; i++) {
    html.push('<li style="padding-left: ');
    html.push(i % 50);
    html.push('" id="item-');
    html.push(i);
    html.push('">Element ');
    html.push(i);
    html.push(' Column ');
    html.push(i % 50);
    html.push('</li>');
}
el.innerHTML = html.join('');

Here are the results in table and diagram formats.

No Method IE 6 IE 7 FF 1.5 FF 2.0 Opera 9
1 createElement() 1403 219 166 328 63
2 createElement() full 1134 - - - -
3 innerHTML 39757 20781 41058 307938 11391
4 innerHTML optimized 10994 46 50 109 31
5 innerHTML/join 400 31 47 125 31
 
6 innerHTML/optimized+ 28934 109 84 172 62
7 innerHTML/join+ 950 78 110 189 62

Benchmark: Adding DOM elements to document

You can view benchmark test and get your own results here.

Conclusions

  • Always use DOM node functions to keep your code standards-compliant. This approach has satisfactory performance and works in all browsers.
  • If you need extremely high performance, use join+innerHTML method, which has best time in benchmark.
  • Never use appending HTML strings to the innerHTML (yeah, if you need append one small element).
  • Opera is fastest browser in the world, but Internet Explorer 7 is fast too, Firefox 2.0 surprised me with his low performance.
  • Never believe fanatics like me and benchmark different approaches by yourself (but don't worry, Microsoft does not paid me for their browser advertisement).

Links to other parts

  • Part 1: Adding DOM elements to document
  • Part 2: Applying styles to elements
  • Part 3: Attaching events
  • Part 4: Multiple anonymous functions (will be published soon)
  • Part 5: Attaching events on demand (will be published soon)
  • Part 6: Element hide and show (will be published soon)
  • Part 7: Elements collection enumeration (will be published soon)
The post JavaScript optimization Part 1: Adding DOM elements to document first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/javascript/javascript-optimization-part-1-adding-dom-elements-to-document/feed/ 18
Extending moo.fx with custom effect (fx.Flash) https://kpumuk.info/javascript/extending-moo-fx-with-custom-effect-fx-flash/ https://kpumuk.info/javascript/extending-moo-fx-with-custom-effect-fx-flash/#comments Sat, 29 Apr 2006 08:54:43 +0000 http://kpumuk.info/php/extending-moo-fx-with-custom-effect-fx-flash/ Several days ago my best friend Alexey Kovyrin asked me to help him to create flashing effect on HTML page. I gave him advice to create this effect using moo.fx library. I wanted to show how to extend it, but I couldn’t keep from creating this effect myself. moo.fx is a superlightweight, ultratiny, megasmall javascript […]

The post Extending moo.fx with custom effect (fx.Flash) first appeared on Dmytro Shteflyuk's Home.]]>
Several days ago my best friend Alexey Kovyrin asked me to help him to create flashing effect on HTML page. I gave him advice to create this effect using moo.fx library. I wanted to show how to extend it, but I couldn’t keep from creating this effect myself.

moo.fx is a superlightweight, ultratiny, megasmall javascript effects library, written with prototype.js. It’s easily to extend it with custom effect and in this post I will show you how you can do this. In this article I’ll show how to create flashing effect: element’s background will smoothly change from one color to another and go back to first color (maybe several times).

To extend fx.Base you can use following construction:

1
2
3
fx.Flash = Class.create();
Object.extend(Object.extend(fx.Flash.prototype, fx.Base.prototype), {  
// ...

Now we need to decide in which format initial colors will be passed. I think the most simple to user is to pass color values in #RRGGBB format, the most popular format in web-design. We need to parse this format to get separate color’s parts (reg, green and blue), therefor it’s necessary to create function that makes hexadecimal => decimal conversion. To assign background color to the element while flashing reverse function is required.

1
2
3
4
5
6
7
8
9
10
11
12
hD: "0123456789ABCDEF",

d2h: function(d) {
    var h = this.hD.substr(d & 15, 1);
    while (d > 15) { d >>= 4; h = this.hD.substr(d & 15, 1) + h; }
    if (h.length == 1) h = "0" + h;
    return h;
},
   
h2d: function(h) {
    return parseInt(h, 16);
}

Now we are ready to develop constructor (method initialize()):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
initialize: function(el, options) {
    this.el = $(el);

    var color_from = (options && options.color_from) || "#ffffff";
    var color_to = (options && options.color_to) || "#ff0000";
    var color_f = this.h2d(color_from.substr(1));
    var color_t = this.h2d(color_to.substr(1));
   
    var _options = {
        red: [color_f >> 16, color_t >> 16],
        green: [(color_f >> 8) & 255, (color_t >> 8) & 255],
        blue: [color_f & 255, color_t & 255],
        count: 1
    };
    Object.extend(_options, options || {});
    if (_options.onComplete) _options.flashOnComplete = _options.onComplete;
    this.setOptions(_options);
}

This function can accept following options:

  • duration – duration in milliseconds of changing color from first to second or vice versa. For example, if you pass count = 3, complete effect execution time will be 3 * 2 * duration (default is 500).
  • onComplete – a function that will get called upon effect completion.
  • transition – transition type. (default is fx.sinoidal)
  • color_from – beginning color (default is #ffffff)
  • color_to – ending color (default is #ff0000)
  • count – flashes count (default is 1)

Effect dependents on onComplete function therefor this parameters is saved to another options variable flashOnComplete.

Function increase() is called during effect. In this function we can calculate current color based on internal variable this.now:

1
2
3
4
5
6
increase: function() {
    var r = this.d2h(this.now * (this.options.red[0] - this.options.red[1]) / 255 + this.options.red[1]);
    var g = this.d2h(this.now * (this.options.green[0] - this.options.green[1]) / 255 + this.options.green[1]);
    var b = this.d2h(this.now * (this.options.blue[0] - this.options.blue[1]) / 255 + this.options.blue[1]);
    this.el.style.backgroundColor = "#" + r + g + b;
}

To call effect function toggle() used. OnComplete is used to repeat effect from ending to beginnig color. It also decrements current count value to make it possible to repeat effect count times.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
toggle: function() {
    if (this.flashCount == undefined) this.flashCount = this.options.count;
    this.options.onComplete = this.onComplete.bind(this);
    this.custom(255, 0);
},

onComplete: function() {
    this.flashCount--;
    if (this.flashCount == 0)
    {
        this.flashCount = undefined;
        this.options.onComplete = this.options.flashOnComplete;
    } else
        this.options.onComplete = this.toggle.bind(this);
    this.custom(0, 255);
}

Thats all. You can download source file here. Samples are shown below this.

This is sample text. Click the link below to view fx.Flash effect in action.
1
var sample1 = new fx.Flash("sample-area", {color_from:"#ffffe3", color_to:"#007f00", count:3, transition:fx.circ, duration:300});

Show effect #1

1
var sample2 = new fx.Flash("sample-area", {color_from:"#ffffe3", color_to:"#7f0000", count:1, duration:600});

Show effect #2

The post Extending moo.fx with custom effect (fx.Flash) first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/javascript/extending-moo-fx-with-custom-effect-fx-flash/feed/ 5