Javascript No Obstrusivo o cuando Ajax es un problema

Posted by joahking
on Jul 08, 08
Ajax ha sido un boom en el desarrollo web en los últimos tiempos, pero mal usado puede crear problemas de rendimiento. Puedes probar una busqueda en Google, pero los puntos problematicos son estos más o menos:

Por ejemplo, los Selects en Cascada mejorarían su rendimiento si mandara al browser todos los datos necesarios y construyera los selects usando OPTGROUP evitando pedir pequeñas cantidades por Ajax cada vez para repintar los selects dependientes cada vez que se cambia la opcion de un padre.

Esto es precisamente lo que intenta resolver Ryan Bates en su railscast Dynamic Select Menus. Su idea es en la vista pedirle javascript a un controlador javascript:
<!-- views/somethings/new.html.erb -->
   <% javascript 'esta_accion' %>

# application_helper.rb
def javascript(*files)
  content_for(:head) { javascript_include_tag(*files) }
end

# y en el javascript_controller
def esta_accion
  @datos = Dato.find :all
end

Luego el erb parseará el views/javascripts/esta_accion.js.erb que se encargará de generarnos un javascript a la medida.

Hasta aquí todo bien, pero esto no nos resuelve el problema completamente. Mirando los logs notamos que para generar la vista new de los somethings estamos haciéndole dos peticiones al Rails.

Fíjate que no solo estamos hablando de mas de una petición a Rails, sino tambien si el proceso es más complejo que mis simples selects estaré repitiendo código del negocio de la acción new de Something en otro controlador.

O sea que eliminamos los muchos accesos al DOM y el Ajax pero a muy mal precio, ¿porqué no reducimos el round-trip a solo una request?

Unobstrusive Javascript

no voy a extenderme diciendo qué es el Javascript No Obstrusivo, para eso están los gurus y Mr. Google.

Resumiendo la idea es sacar el javascript del html y pegarle eventos a los elementos desde un javascript después que la página esté cargada:

<!-- algún html define el elemento -->
   <button id="alertable">Click me!</button>

<!-- algún javascript le pega el evento onclick -->
  document.observe(
     "dom:ready", 
     function() {
         document.getElementById("alertable").addEventListener( 'click',
            function() { 
               alert("Gracias, he esperado toda mi vida este momento!"); 
            }, 
         false);
      });
Hay un screencast muy bueno en railsenvy sobre cómo integrar UJS en Rails. Quedaría así resumiendo:
<!-- en el layout -->
<head>
    <%= yield :unobstrusive_javascript %>
</head>

<!-- views/algos/show.html.erb -->
<% content_for :unobtrusive_javascript do -%>
  <script type="text/javascript" charset="utf-8">
    document.observe(
        "dom:ready", 
        arrancaUserInterface('<%= @datos_para_la_UI.to_json %>'), 
        false
    );
  </script>
<% end %>

Ahora ya no necesitamos más el javascripts_controller, estoy contento con esta solución pero igual me falta la elegancia de la solución de Ryan Bates, donde no tenía javascript en el head de mi html, sino separado en un archivo javascript.

Talvez UJS4Rails es lo que estoy buscando, pero…

Si este fuera el mejor de los mundos posibles ¿cómo querría que esto quedara?

Me gustaría que en el procesamiento MVC de la petición Rails transformara la V en V + js, así tendriamos unobstrusive js out of the box, REST y algunas otras golosinas. Pero quien sabe si el futuro….

A este otro habria que darle una oportunidad

El plugin cascading javascripts carga en el javascript_include_tag macro los archivos javascript siguientes (si existen) en este orden:

  • application.js
  • #{controller_name/action_name}.js (ej. home/index.js, customers/new.js, etc).
Comments

Leave a response

Comment