Saturday, September 13, 2014

Unresponsive Scripts and Javascript's Lack of Sleep



Working on a single-page app using a MV* library? You've probably had this wonderful dialog popup at some point. If your Javascript is running without taking a breadth, the browser will get chippy and start alerting the user that something has gone awry. While its most likely true, popping up messages the user doesn't understand really doesn't help. Even worse are the solutions to turn off Javascript because many sites still function even if scripting is disabled. Unfortunate advice in today's Internet.

In many cases, its a loop with a significant number of iterations that is probably triggering any number of more complex operations. Without yielding to the browser from time-to-time, it will create an unresponsive experience for your user (dialog or not). If you've programmed in other languages, you're immediate go to solution might be to sprinkle in time kind of sleep calls in those process intensive loops. Unfortunately, there is no sleep function in Javascript. The only mechanism to break out of a call stack is the setTimeout function. However, it does not work like sleep in other languages where the current execution point blocks while something else runs and then returns back to the next line after the sleep timeout. Instead, it just keeps on running:

Monday, September 8, 2014

Multi-Option Picker using Bootstrap Dropdowns with Checkboxes

I wanted check boxes in my Bootstrap dropdown menu so the user could pick from several different options and see which options were already selected. The menu's default behavior is to hide once the user clicks on it. This meant I needed to cancel the click event to prevent that behavior. Unfortunately, if the user clicked a checkbox, it wouldn't show as checked since the click was being canceled (try clicking the checkbox versus the anchor and notice how it doesn't toggle):

See the Pen Bootstrap Dropdown with Checkboxes: Can't Check by bseth99 (@bseth99) on CodePen.



For reference, this is the markup for the dropdown with the checkboxes:


<ul class="dropdown-menu">
<li>
<a href="#" class="small" data-value="option1" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 1
</a>
</li>
<li>
<a href="#" class="small" data-value="option2" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 2
</a>
</li>
<li>
<a href="#" class="small" data-value="option3" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 3
</a>
</li>
<li>
<a href="#" class="small" data-value="option4" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 4
</a>
</li>
<li>
<a href="#" class="small" data-value="option5" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 5
</a>
</li>
<li>
<a href="#" class="small" data-value="option6" tabIndex="-1">
<input type="checkbox"/>&nbsp;Option 6
</a>
</li>
</ul>


My goal is to use one event handler for both the anchor and the check box. On each click, toggle the option, and ensure the check box reflects this choice. When you click the anchor, the check box needs to be set. However, if you click the check box, it wouldn't need to be set, but to be consistent and use one handler, I just set it anyways (I saw no reason to add any more sophisticated element detection to the code):

var options = [];

$( '.dropdown-menu a' ).on( 'click', function( event ) {

   var $target = $( event.currentTarget ),
       val = $target.attr( 'data-value' ),
       $inp = $target.find( 'input' ),
       idx;

   if ( ( idx = options.indexOf( val ) ) > -1 ) {
      options.splice( idx, 1 );
      $inp.prop( 'checked', false );
   } else {
      options.push( val );
      $inp.prop( 'checked', true );
   }

   $target.blur();

   return false;
});
I want the return false in there to prevent the dropdown from closing and, secondarily, to ensure the href="#" doesn't affect my router. I could remove the href from the anchor, but then I'd lose the hand cursor on hover. I could style it have the cursor, but I'd still be left with the auto-closing menu which I don't want since the user may want to pick other options. That leaves me with the conundrum of dealing with a direct click on the box which also is a click on the anchor which needs to be canceled but canceling it also doesn't check the box properly. I can think of several ways around it - all adding way more code than makes sense for such a seemingly simple problem. After some toiling, I finally found a very easy work-around. It occurred to me that I just needed to check the box after all the events finished running. That means I needed to be outside the current call stack to check the box. Using setTimeout with a zero delay does just that so I wrapped that bit of code in a setTimeout and - viola - working checkboxes:


   setTimeout( function() { $inp.prop( 'checked', true ) }, 0);



And here's the whole working example:

See the Pen Bootstrap Dropdown with Checkboxes: Working by bseth99 (@bseth99) on CodePen.



And with that, the Bootstrap drop down become just that much more useful.

Tuesday, September 2, 2014

Triggering CSS-Only :hover and :focus Transitions

I've been making an attempt to use CSS-only for transitions including actually triggering them. The best mechanism to trigger a transition is using the :hover pseudo-select on an anchor tag. Other than :focus, its really the only one which will reset its state. I've seen hacks using :active and :target but it seem those are really stretching what makes sense based on the capabilities of CSS. To really eliminate JS, more state selectors are needed that enable attaching transitions and animations. For now, I'm exploring using :hover to create a simple carousel-like widget.

Before jumping into the final project, I quickly tested the idea:

See the Pen Simple No-JS Hover Animation by bseth99 (@bseth99) on CodePen.



This is a very simple case to play with the idea. With some actual styling, it would work really well as tooltip. You can see the .pop class defines the transition and the initial state of the element. The :hover selector is used to change the value which causes it to animate into view.

Moving on to the carousel idea, I setup three anchors which serve as hot spots to quickly transition to that slide in the widget. I also setup the carousel to continuously animate through each slide until the user hovers over the anchor which interrupts the normal animation and immediately transitions to the slide represented by the link:

See the Pen Hnoxg by bseth99 (@bseth99) on CodePen.



The difference in this setup compared to the simple case above, is instead of embedding the transitioning content into the anchor tag, the whole carousel is a sibling of each of the anchors. This relationship makes it possible to add other anchors tags to the slides as needed and makes the whole setup easier. Selecting those elements uses a selector I've rarely used (if ever). The "~" will select a sibling inside the same parent even if its not adjacent to another element. This is important since I have more than one anchor and clearly the first one is not immediately next to the main carousel element.

The next step is to define the transition and animation on the carousel. They are attached to the .slider element which is a child of the main carousel element. Its setup to scroll inside this container which hides the overflow to create the illusion of only one slide showing at a time. Each slide then becomes a child of slider with unique class names so they can be targeted as the mouse hovers over each anchor:

.scroller {
  transition: left 400ms ease-in-out;
  animation: autorun 5s;
  animation-delay: 500ms;
  animation-iteration-count: infinite;
}


Before forcing the transition, the animation needs to be turned off, otherwise, it will get jumpy:

.trigger:hover ~ .container > .scroller {
   animation: none;
}


Then, each position can be defined for the slides:

.trigger:hover.r ~ .container > .scroller {
  left: 0;
}

.trigger:hover.g ~ .container > .scroller {
  left: -100px;
}

.trigger:hover.b ~ .container > .scroller {
  left: -200px;
}


One additional improvement is to allow the user to click which will hold the current slide in place. Right now, as soon as you hover off the anchor, the carousel rewinds to the beginning and starts the animation over again. We can take advantage of the fact that when you click on an anchor it receives focus and remains there until clicking off the element. Only a few minor changes are required to add this feature. First, the above .trigger:hover styles need to include an additional .trigger:focus selector:

.trigger:hover.r ~ .container > .scroller,
.trigger:focus.r ~ .container > .scroller {
  left: 0;
}

...



And to enable the anchor to be focusable, the tabindex needs to be set:

<a href="#" class="trigger r" tabindex="0">
</a>



Here is the revised version using both :hover and :focus to create the interaction with the widget:

See the Pen iobaE by bseth99 (@bseth99) on CodePen.



Its fairly simple but if you don't need anything exotic you can get by quite well with some carefully laid out HTML which takes advantage of the abilities of CSS. While I called this a carousel, it certainly is not limited to that design. Any situation that calls for links that transition through some set of content can take advantage of this approach without any need to write a line of Javascript.

Monday, August 25, 2014

Caching Ruby Sequel Models to Reduce Object Allocations and Database Load

Caching seems to be an inevitable part of most applications. The strategies you employ application-to-application will differ depending on use. Write intensive areas will receive little benefit while read intensive areas can see significant performance boosts. As you design and build your application, you should be able to name off data stores that remain fairly static and can readily be held in memory with little risk of becoming stale. I've been using the Sequel ORM to build my models on PostgreSQL and my number one candidate for caching are contact details. Just about everything output from the application include at least one, if not 20 or more references to the contact model. Further research found that within one request, many contact lookups were actually the same contact record which made it a perfect candidate for caching at least within the request.

Since most of these references are done through a primary key lookup on the table:

   ...
   contact = Contact[other_object.contact_id]
   ...


I figured I could proxy the [] method on the class and add my caching logic there.

I found a gem called lru_redux which, if using Ruby 1.9+, takes advantage of the fact that a Hash is ordered. This makes a very efficient and easy to use LRU cache to keep a finite set of very active models:

class Contact < Sequel::Model
   attr_accessor :last_reload_time

   class << self
      
      @@cache = LruRedux::Cache.new(100)
     
      # Override [] to add in caching logic
      def []( rid )
         if ( rec = @@cache[rid] )
            # Model is found in cache, no need to load it from the DB
            if rec.last_reload_time < 5.minutes.ago
               # Cached model instance is stale, reload it
               rec.reload
               rec.last_reload_time = Time.now.utc
            end
         else
            rec = super(rid)
            if rec
               # Don't cache nil models (id not found in DB)
               rec.last_reload_time = Time.now.utc
               @@cache[rid] = rec
            end

         end
         rec
      end
   end

end


Since I'm going to leave the models in memory between requests, I still need to ensure a model doesn't get stuck there indefinitely without reloading on a periodic basis. Maintaining the last_reload_time instance variable ensures data stay fairly up-to-date. Since I know these don't change too often, five minutes is probably conservatively low. You might also ask why not just reload the model when it changes? That reload would only be local to the current process and not across the multiple processes spread over several servers I have running. Those other processes have no knowledge of the change and, in an effort to not make this more complicated, I settled on a simple timeout and fairly short LRU list.

With the above caching strategy, I chopped a few hundred milliseconds off my most used end point. The savings really were two-fold. First, the caching removes the round trip to the database and the processing time required to parse the data and build the model. Secondly, because these objects are more persistent, there is less object allocations on each request and thus, less garbage collection. Since GC gets expensive, reducing that alone made a significant improvement.

The above example may not solve every problem. There's no replacement for studying your application's specific request patterns, execution paths, and data structures. Performance tuning is not a simple task but having as many tools at your disposal to solve various bottlenecks can make the process a whole lot smoother.

Saturday, June 28, 2014

Learning to Graph with D3

I've been meaning to play with D3 for quite some time. Maybe the only thing stopping me was the seemingly overwhelming amount of features available in the library. There's a definite learning curve involved to get in the right mindset required to use D3. However, once you get there, its actually really easy to use and, surprisingly, does a lot of the heavy lifting for you. As you navigate through the documentation, you need to separate the basics from the advanced features. If you need a static graph, you only need to learn a subset of the library to be successful. Once you get that foundation in place, you can build into transitions, interactivity, and layouts.

For my first foray into the world of D3, I chose to keep things as simple as possible and focus on deconstructing the multivariate example graph to attempt to isolate the basic components of a graph. I was really interested in what was actually happening at each step and how the pieces fit together. Below, I'll attempt to iteratively build the example one feature at a time to get to the final product. I consider each step, a basic component of any graph so you should be able to take the pieces and assemble them together to rapidly start your own "first" graph.