performance | 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:13:28 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 Weekly Link Dump #1 https://kpumuk.info/links/weekly-link-dump-1/ https://kpumuk.info/links/weekly-link-dump-1/#comments Mon, 14 Sep 2009 09:48:01 +0000 http://kpumuk.info/?p=971 This is a first link dump in this blog, where I will list all interesting links that I have found in Internet. I plan to post link dumps once a week, so stay tuned to read most useful stuff with no effort. Todays topics are: organizing your CSS, top mistakes made by WordPress plugins authors, […]

The post Weekly Link Dump #1 first appeared on Dmytro Shteflyuk's Home.]]>
This is a first link dump in this blog, where I will list all interesting links that I have found in Internet. I plan to post link dumps once a week, so stay tuned to read most useful stuff with no effort. Todays topics are: organizing your CSS, top mistakes made by WordPress plugins authors, ways MySQL uses indexes, and the git version control advantages over the Subversion.

Beautiful CSS: Organizing Your Stylesheets

When I first took the plunge into CSS several years ago, one of my biggest frustrations was stylesheet organization. I scoured source code from popular sites trying to figure how they accomplished various layout effects. But tracking back and forth from stylesheets to HTML proved to be a difficult task. Unfortunately , that separation of style and content that makes CSS so awesome can also make it difficult to understand. Adding to that difficulty is the fact that each designer may have a different way of organizing stylesheets. If you inherit someone else’s site, this can cause some problems. In a perfect world everyone’s CSS would be well-organized, easy to scale, and easy to understand. We may not be able to attain such CSS Nirvana but we can at least make it easier on ourselves and those we work with by following this set of guidelines.

A nice article about organization of your CSS code. Author recommends to split your CSS code to several sections (universal styles, library styles, template layouts, individual page styles.) Also he proposes to indent styles related to nested HTML elements.

Top 10 Most Common Coding Mistakes in WordPress Plugins

As promised, I’m going to share a list of the most common mistakes, errors, misunderstandings, bad habits or wrong design decisions I’ve encountered while reviewing all these 43 plugins. Some are highly critical stuff (I’ve contacted 3 plugins authors after finding serious security holes in their plugin), some are more potential annoyances than real bugs, or are just causing a waste of server resources that could be avoided, but all have something in common: they’re trivial to fix. I’ve classified them in two parts: 10 bad code signs, plus a bonus with design decisions that suck. If you consider yourself a semi experienced coder or better, be sure to skip this article, you’re not going to learn a thing.

A comprehensive list of common pitfalls of WordPress plugins authors. If you maintain a plugin, please read this article carefully, most of mistakes are quite common (yes, I found several issues with my ones

3 ways MySQL uses indexes

I often see people confuse different ways MySQL can use indexing, getting wrong ideas on what query performance they should expect. There are 3 main ways how MySQL can use the indexes for query execution, which are not mutually exclusive, in fact some queries will use indexes for all 3 purposes listed here.

You should read it. Period! Article covers all ways how MySQL uses indexes: filtering rows, sorting data, and reading data.

Why You Should Switch from Subversion to Git

You may have heard some hubbub over distributed version control systems recently. You may dismiss it as the next hot thing, the newest flavor of kool-aid currently quenching the collective thirst of the bandwagon jumpers. You, however, have been using Subversion quite happily for some time now. It has treated you pretty well, you know it just fine and you are comfortable with it – I mean, it’s just version control, right?

Yet another article about git and what features make it so wonderful tool for any developer. Author covers main features of this version control system, and explains how it could improve your work and boost your productivity. Hey Subversion (SourceSafe, CVS, etc) users, I do not accept any excuses, you definitely should read it. Yes, right now!

The post Weekly Link Dump #1 first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/links/weekly-link-dump-1/feed/ 1
Scribd open source projects https://kpumuk.info/development/scribd-open-source-projects/ Tue, 08 Sep 2009 02:06:05 +0000 http://kpumuk.info/?p=918 It’s time to summarize what we have done for the Open Source community. Scribd is pretty open company, we release a lot of code into the public after a time (sometimes it is short, sometimes it is not). Here I want to mention all the code we have opensourced. Please take into account that time […]

The post Scribd open source projects first appeared on Dmytro Shteflyuk's Home.]]>
It’s time to summarize what we have done for the Open Source community. Scribd is pretty open company, we release a lot of code into the public after a time (sometimes it is short, sometimes it is not). Here I want to mention all the code we have opensourced. Please take into account that time is moving on, so we are publishing more and more code. I will update this post periodically, so stay tuned. Follow me on Twitter to get instant updates.

Table of Contents

Here is the list of our projects in alphabetical order:

  • bounces-handler — Email Bounces Processing System with Rails plugin to prevent Rails mailers from sending any messages to a blocked addresses.
  • db-charmer — ActiveRecord Connections Magic (slaves, multiple connections, etc).
  • easy-prof — Simple and easy to use Ruby code profiler, which could be used as a Rails plugin.
  • Fast Sessions — Sessions class for ActiveRecord sessions store created to work fast (really fast).
  • loops — Simple background loops framework for Ruby on Rails and Merb.
  • magic-enum — Method used to define ENUM-like attributes in your model (int fields actually).
  • rlibsphinxclient — A Ruby wrapper for pure C searchd client API library.
  • rscribd — Ruby client library for the Scribd API.
  • Rspec Cells — A library for testing applications that are using Cells in RSpec.
  • Scribd Desktop Uploader — A fully native Cocoa Macintosh uploader app for the Scribd.com website.

bounces-handler

Bounces-handler package is a simple set of scripts to automatically process email bounces and ISP’s feedback loops emails, maintain your mailing blacklists and a Ruby on Rails plugin to use those blacklists in your RoR applications.

This piece of software has been developed as a part of more global work on mailing quality improvement in Scribd.com, but it was one of the most critical steps after setting up reverse DNS records, DKIM and SPF.

Links: Project Home Page on GitHub | Introduction Blog Post | RDoc Documentation.

db-charmer

DbCharmer is a simple yet powerful plugin for ActiveRecord that does a few things:

  • Allows you to easily manage AR models’ connections (switch_connection_to method)
  • Allows you to switch AR models’ default connections to a separate servers/databases
  • Allows you to easily choose where your query should go (Model.on_db methods)
  • Allows you to automatically send read queries to your slaves while masters would handle all the updates.
  • Adds multiple databases migrations to ActiveRecord

It requires Ruby on Rails version 2.3 or later. The main purpose of this plugin is to put all the databases-related code we have been using in Scribd for a while into a single easy-to use package.

Links: Project Home Page on GitHub | Test Rails Application on GitHub | RDoc Documentation.

easy-prof

Simple and easy to use Ruby code profiler, which could be used as a Rails plugin. The main idea behind the easy-prof is creating check points and your code and measuring time needed to execute code blocks. Here is the example of easy-prof output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[home#index] Benchmark results:
[home#index] debug: Logged in user home page
[home#index] progress: 0.7002 s [find top videos]
[home#index] progress: 0.0452 s [build categories list]
[home#index] progress: 0.0019 s [build tag cloud]
[home#index] progress: 0.0032 s [find featured videos]
[home#index] progress: 0.0324 s [find latest videos]
[home#index] debug: VIEW STARTED
[home#index] progress: 0.0649 s [top videos render]
[home#index] progress: 0.0014 s [categories render]
[home#index] progress: 2.5887 s [tag cloud render]
[home#index] progress: 0.0488 s [latest videos render]
[home#index] progress: 0.1053 s [featured video render]
[home#index] results: 3.592 s

From this output you can see what checkpoints takes longer to reach, and what code fragments are pretty fast.

Links: Project Home Page on GitHub | Introduction Blog Post | RDoc Documentation.

Fast Sessions

FastSessions is a sessions class for ActiveRecord sessions store created to work fast (really fast). It uses some techniques which are not so widely known in developers’ community and only when they cause huge problems, performance consultants are trying to help with them.

FastSessions plugin was born as a hack created for Scribd.com (large RoR-based web project), which was suffering from InnoDB auto-increment table-level locks on sessions table.

So, first of all, we removed id field from the table. Next step was to make lookups faster and we’ve used a following technique: instead of using (session_id) as a lookup key, we started using (CRC32(session_id), session_id) — two-columns key which really helps MySQL to find sessions faster because key cardinality is higher (so, mysql is able to find a record earlier w/o checking a lots of index rows). We’ve benchmarked this approach and it shows 10–15% performance gain on large sessions tables.

And last, but most powerful change we’ve tried to make was to not create database records for empty sessions and to not save sessions data back to database if this data has not been changed during current request processing. With this change we basically reduce inserts number by 50-90% (depends 0n application).

All of these changes were implemented and you can use them automatically after a simple plugin installation.

There is a fork patched by mudge for full compatibility with Ruby on Rails version 2.3 or later.

Links: Project Home Page on Google Code | Introduction Blog Post | Fork on GitHub Compatible with Rails 2.3 and Later.

loops

loops is a small and lightweight library for Ruby on Rails, Merb and other frameworks created to support simple background loops in your application which are usually used to do some background data processing on your servers (queue workers, batch tasks processors, etc).

Originally loops plugin was created to make our own loops code more organized. We used to have tens of different modules with methods that were called with script/runner and then used with nohup and other not so convenient backgrounding techniques. When you have such a number of loops/workers to run in background it becomes a nightmare to manage them on a regular basis (restarts, code upgrades, status/health checking, etc).

After a short time of writing our loops in more organized ways we were able to generalize most of the loops code so now our loops look like a classes with a single mandatory public method called run. Everything else (spawning many workers, managing them, logging, backgrounding, pid-files management, etc) is handled by the plugin itself.

Links: Project Home Page on GitHub | Introduction Blog Post | RDoc Documentation.

magic-enum

Method used to define ENUM-like attributes in your model (int fields actually). It’s easier to show what it does in code rather than to explain in plain English:

1
2
3
4
5
6
7
Statuses = {
  :unknown => 0,
  :draft => 1,
  :published => 2,
  :approved => 3
}
define_enum :status, :default => 1, :raise_on_invalid => true, :simple_accessors => true

is identical to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Statuses = {
  :unknown => 0,
  :draft => 1,
  :published => 2,
  :approved => 3
}
StatusesInverted = Statuses.invert

def status
  StatusesInverted[self[:status].to_i] || StatusesInverted[1]
end

def status=(value)
  raise ArgumentError, "Invalid value "#{value}" for :status attribute of the #{self.class} model" if
  Statuses[value].nil?
  self[:status] = Statuses[value]
end

def unknown?
  status == :unknown
end

def draft?
  status == :draft
end

def published?
  status == :published
end

def approved?
  status == :approved
end

This plugin was originally developed for Best Tech Videosand later was cleaned up in Scribd repository and released to the public.

Links: Project Home Page on GitHub | RDoc Documentation.

rlibsphinxclient

A Ruby wrapper for pure C searchd client API library. It works much faster than any Ruby client for Sphinx, so you can check it to ensure you application works as fast as possible.

Please note: this is *highly experimental* library so use it at your own risk.

Links: Project Home Page on GitHub | RDoc Documentation.

rscribd

Ruby client library for the Scribd API. This gem provides a simple and powerful library for the Scribd API, allowing you to write Ruby applications or Ruby on Rails websites that upload, convert, display, search, and control documents in many formats. For more information on the Scribd platform, visit the Scribd Platform Documentation page.

The main features are:

  • Upload your documents to Scribd’s servers and access them using the gem
  • Upload local files or from remote web sites
  • Search, tag, and organize documents
  • Associate documents with your users’ accounts

Links: Project Home Page on GitHub | Scribd Platform Documentation | RDoc Documentation.

Rspec Cells

This plugin allows you to test your cells easily using RSpec. Basically, it adds an example group especially for cells, with several helpers to perform cells rendering.

If you are not sure what is cells, please visit its home page.

Spec for a regular cell could look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
describe VideoCell do
    integrate_views

    context '.videos' do
      it 'should initialize :videos variable' do
        params[:id] = 10
        session[:user_id] = 20
        opts[:opt] = 'value'
        result = render_cell :videos, { :videos => [] }, :slug => 'hello'
        result.should have_tag('div', :class => :videos)
      end
    end
  end

Links: Project Home Page on GitHub | Cells Home Page | Cells Home Page on GitHub.

Scribd Desktop Uploader

A fully native Cocoa Macintosh uploader app for the Scribd.com website. Supports following features:

  • Upload many files at once from your desktop.
  • Edit titles, tags, and other metadata before uploading.
  • Quickly and easily manage bulk uploads, straight from your desktop.
  • Right-click to start uploading files directly to Scribd (Windows only).

Links: Project Home Page on GitHub | Home Page on Scribd.com.

Changelog

  • September 9, 2009
    • Fixed a link to GitHub homepage of the rspec-cells plugin.
  • September 8, 2009
The post Scribd open source projects first appeared on Dmytro Shteflyuk's Home.]]>
Creating a simple but powerful profiler for Ruby on Rails https://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/ https://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/#comments Wed, 26 Aug 2009 21:23:15 +0000 http://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/ You are developing a large Web application. Controllers are full of complex data retrieving logic, views contain tons of blocks, partials, loops. One day you will receive an email with user complaints about some of your pages slowness. There are many profiling tools, some of them are easy (ruby-prof), others are large and complex (newrelic), […]

The post Creating a simple but powerful profiler for Ruby on Rails first appeared on Dmytro Shteflyuk's Home.]]>
You are developing a large Web application. Controllers are full of complex data retrieving logic, views contain tons of blocks, partials, loops. One day you will receive an email with user complaints about some of your pages slowness. There are many profiling tools, some of them are easy (ruby-prof), others are large and complex (newrelic), but regardless of this it’s really hard to find the particular place where you have a real bottleneck. So we created really simple, but über-useful tool for ruby code profiling.

First of all, we need to decide what features we need from this tool. Don’t know about you, but all I need is to measure execution time of particular ruby code block. Here is what I mean:

1
2
3
4
5
6
7
8
9
10
11
12
13
[home#index] debug: Logged in user home page
[home#index] progress: 0.7002 s [find top videos]
[home#index] progress: 0.0452 s [build categories list]
[home#index] progress: 0.0019 s [build tag cloud]
[home#index] progress: 0.0032 s [find featured videos]
[home#index] progress: 0.0324 s [find latest videos]
[home#index] debug: VIEW STARTED
[home#index] progress: 0.0649 s [top videos render]
[home#index] progress: 0.0014 s [categories render]
[home#index] progress: 2.5887 s [tag cloud render]
[home#index] progress: 0.0488 s [latest videos render]
[home#index] progress: 0.1053 s [featured video render]
[home#index] results: 3.592 seconds

So what do we see from this output? There are two slow blocks: top videos retrieving and tag cloud rendering. Now we just know what to do to make this page faster.

Let’s write the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
module EasyProfiler
  class Profile
    @@profile_results = {}

    cattr_accessor :enable_profiling
    @@enable_profiling = false
   
    cattr_accessor :print_limit
    @@print_limit = 0.01
   
    def self.start(name, options = {})
      options[:enabled] ||= @@enable_profiling
      options[:limit] ||= @@print_limit
      return NoProfileInstance.new unless options[:enabled]

      if @@profile_results[name]
        puts "EasyProfiler::Profile.start() collision! '#{name}' is already started!"
        return NoProfileInstance.new
      end
     
      @@profile_results[name] = ProfileInstance.new(name, options)
    end
   
    def self.stop(name, options = {})
      options[:enabled] ||= @@enable_profiling
      options[:limit] ||= @@print_limit
      return unless options[:enabled]

      unless @@profile_results[name]
        puts "EasyProfiler::Profile.stop() error! '#{name}' is not started yet!"
        return false
      end
     
      total = @@profile_results[name].total
     
      if total > options[:limit]
        @@profile_results[name].buffer_checkpoint("results: %0.4f seconds" % total)
        @@profile_results[name].dump_results
      end
     
      @@profile_results.delete(name)
    end
  end
 
  class ProfileInstance
    def initialize(name, options = {})
      @name = name
      @start = @progress = Time.now.to_f
      @buffer = []
    end
   
    def progress(message)
      progress = (now = Time.now.to_f) - @progress
      @progress = now
      buffer_checkpoint("progress: %0.4f seconds [#{message}]" % progress)
    end
   
    def debug(message)
      @progress = Time.now.to_f
      buffer_checkpoint("debug: #{message}")
    end
   
    def total
      Time.now.to_f - @start
    end
   
    def buffer_checkpoint(message)
      @buffer << message
    end
   
    def dump_results
      profile_logger.info("[#{@name}] Benchmark results:")
      @buffer.each do |message|
        profile_logger.info("[#{@name}] #{message}")
      end
    end

    def profile_logger
      root = Object.const_defined?(:RAILS_ROOT) ? "#{RAILS_ROOT}/log" : File.dirname(__FILE__)
      @profile_logger ||= Logger.new(root + '/profile.log')
    end
  end
 
  class NoProfileInstance
    def progress(message)
    end

    def debug(message)
    end
  end
end

We have defined two class attributes: EasyProfiler::Profile.enable_profiling (to be able to disable or enable profiler globally) and EasyProfiler::Profile.print_limit (to filter out from log code blocks that are fast enough).

Then we defined two methods, which accept name of profile session (for example, “home#index”), and hash of options. Possible options are :enabled (to enable profiling of particular block) and :limit (limit in seconds to filter out fast code fragments).

Method start returns an instance of profiler, which will be used to print check points. It contains two useful methods: debug (to display custom message) and progress (to display a message along with time spent since last checkpoint). Both methods define a new checkpoint.

To simplify usage, let’s create a helper:

1
2
3
4
5
6
7
module Kernel
  def easy_profiler(name, options = {})
    yield EasyProfiler::Profile.start(name, options)
  ensure
    EasyProfiler::Profile.stop(name, options)
  end
end

And now example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class HomeController < ApplicationController
  def index
    easy_profiler('home#index', :enabled => profile_request?, :limit => 2) do |p|
      p.progress 'logged in user home page'
     
      @top_videos = Video.top(:limit => 10)
      p.progress 'find top videos'

      @categories = Category.all(:order => 'name DESC')
      p.progress 'build categories list'

      @tag_cloud = Tag.tag_cloud(:limit => 200)
      p.progress 'build tag cloud'
     
      @featured_videos = Video.featured(limit => 5)
      p.progress 'find featured videos'

      @latest_videos = Video.latest(:limit => 5)
      p.progress 'find latest videos'
     
      @profiler = p
      p.debug 'VIEW STARTED'
    end
  end

  private
 
    # Method returns +true+ if current request should ouput profiling information
    def profile_request?
      params['_with_profiling'] == 'yes'
    end
end

and view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  <div id="top_videos">
    <%= render :partial => 'top_videos' %>
    <% @profiler.progress 'top videos render' %>
  </div>
 
  <div class="tabs">
    <ul id="taxonomy">
      <li><a href="#" id="categories" class="current">Categories</a></li>
      <li><a href="#" id="tags">Tags</a></li>
    </ul>
    <div class="categories_panel">
      <%= render :partial => 'categories' %>
      <% @profiler.progress 'categories render' %>
    </div>
    <div class="categories_panel hidden">
      <%= render :partial => 'tag_cloud' %>
      <% @profiler.progress 'tag cloud render' %>
    </div>
  </div>
 
  <div class="box">
    <div id="latest">
      <%= render :partial => 'videos', :videos => @latest_videos %>
      <% @profiler.progress 'latest videos render' %>
    </div>
    <div id="featured">
      <%= render :partial => 'videos', :videos => @featured_videos %>
      <% @profiler.progress 'featured video render' %>
    </div>
  </div>

As you can see from this example, profiler will be enabled only when you pass a _with_profiling parameter with value yes: http://example.com/home?_with_profiling=yes.

That’s all. If you have any question, feel free to post a comment or contact me.

Update: I have created a Rails plugin called easy-prof, which is hosted on GitHub. It’s more powerful and feature complete, so feel free to grab sources and play with it by yourself (check the RDoc documentation at rdoc.info). Do not forget to drop me a line about your feelings.

The post Creating a simple but powerful profiler for Ruby on Rails first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/feed/ 1
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
Rails is just… https://kpumuk.info/ruby-on-rails/rails-is-just/ Fri, 27 Apr 2007 17:26:25 +0000 http://kpumuk.info/development/rails-is-just/ Rails is just an interface to the memcached? Cache the Hell out Everything 90% API Requests — cache them Read the Scaling Twitter.

The post Rails is just… first appeared on Dmytro Shteflyuk's Home.]]>
Rails is just an interface to the memcached?

Cache the Hell out Everything
90% API Requests — cache them

Read the Scaling Twitter.

The post Rails is just… first appeared on Dmytro Shteflyuk's Home.]]>
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