30 diciembre, 2008

Carga asíncrona de scripts

Es un hecho conocido que cada carga de un archivo de script de la forma habitual (<script src="...">) bloquea todos las descargas (imágenes, CSS, scripts) y elementos que aparezcan a continuación (Demo). La forma de remediarlo es cargar los scripts de forma asíncrona, aunque eso genera un nuevo problema, el que coordinar las referencias a código que puede no haberse terminado de cargar todavía y del que habría que comprobar la disponibilidad antes de utilizarlo.

Para solucionarlo se puede optar por varias posibilidades: usar el evento onload de la ventana, que tiene el problema de no ejecutar el código tan pronto como sería posible; usar el evento onreadystatechange del script de forma que se ejecute sólo cuando el código referenciado esté disponible, aunque resulta más complejo de implementar; y usar una llamada a una función callback anunciando la disponibilidad al final de la carga del código referenciado, pero exige tener el control del código que se va a cargar para posibilitar esa llamada.

Sin embargo, aprovechando la técnica de reaprovechar tags script que John Resig descubrió, es posible acercar el código que va a referenciar al objeto que se está cargando en el instante en que está disponible. Recordemos la técnica:

<script type="text/javascript" src="circular/jquery-1.2.3.min.js" onload="eval(this.innerHTML)">
alert($); // se ejecuta sólo cuando jQuery ya está disponible
</script>


Si la petición de carga de esos objetos se realiza una vez que la página ya está cargada (lazy loading) los tiempos mejoran drásticamente manteniendo la funcionalidad. Para ello, hay que lanzar la petición de carga en el evento onload de la página (cuando el usuario percibe la página como ya cargada):

window.onload = function() {
    var script = document.createElement('script');
    script.src = "sorttable-async.js";
    script.text = "sorttable.init()";
    document.getElementsByTagName('head')[0].appendChild(script);
}


Esta técnica de Steve Souders se explica en High Performance Web Sites. Via Ajaxian.

26 diciembre, 2008

Donde no llega el navegador

Google Gears es un proyecto de Google para extender las funciones que ofrecen los navegadores y facilitar así la creación de aplicaciones web. Las funciones disponibles son:

  • LocalServer permite almacenar en caché y proporcionar recursos de aplicaciones (HTML, JavaScript, imágenes, etc.) de forma local. Esto y la base de datos del siguiente punto permiten que las aplicaciones web puedan funcionar incluso cuando no se dispone de conexión activa.
  • Database permite almacenar datos localmente en una base de datos relacional (basada en SQLite) en la que se pueden realizar todo tipo de búsquedas.
  • WorkerPool permite que tus aplicaciones web sean más receptivas, al realizar operaciones con recursos intensivos de forma asíncrona. Es una especie de implementación de hilos concurrentes que se ejecutan de forma independiente del código de la propia página.
  • API de geolocalizacion que permite acceder a la posición geográfica del usuario usando información sobre la red que está utilizando (Wifi o IP).
  • API Blob para gestionar bloques de datos binarios como imágenes.
  • API de acceso a archivos locales.
  • API HTTPRequest para optimizar el envío de información desde el navegador.
  • API Timer implementa un reloj tal y como se indica en la especificación de WhatWG y que resulta especialmente útil al trabajar con WorkerPool ya que los hilos no tienen acceso al objeto Window.
Por dónde empezar. Tutorial. Arquitectura. Seguridad. Herramientas.


Yahoo! BrowserPlus es una tecnología que permite crear aplicaciones web con capacidades de aplicación de escritorio. Por ejemplo, puede añadir o actualizar servicios programáticamente sin recargar el navegador o la página (con la aprobación del usuario); o tareas tan extravagantes como comunicarse con un mando de la Nintendo Wii desde Javascript. Los servicios disponibles una vez instalado (está disponible para Mac y Windows) son:
  • DragAndDrop permite arrastrar archivos desde el escritorio hasta la página actual.
  • FileAccess permite acceder al contenido de los archivos que seleccione el usuario desde la página.
  • FileBrowse es un diálogo de selección de archivos.
  • FileChecksum permite comprobar la validez de un archivo (con MD5) en el lado del usuario.
  • FlickrUploader facilita la autorización y el envío de fotos a Flickr.
  • ImageAlter usa ImageMagick para modificar imagenes localmente.
  • InactiveServices explora servicios disponibles e inactivos que puedan ser descargados y activados.
  • JsonRequest permite realizar consultas JSON seguras entre dominios.
  • Log ofrece acceso a sistemas de registro.
  • Motion permite aprovechar un sensor de movimiento disponible (o la posición del ratón en su defecto) para deducir la orientación del dispositivo.
  • Notify permite enviar notificaciones al escritorio (soporta Growl en Mac).
  • PStore ofrece un área de almacenamiento de datos persistente.
  • RubyInterpreter permite usar otros servicios escritos con Ruby. Ejemplo.
  • TextToSpeech aprovecha el servicio de sintetizador de voz del sistema operativo.
  • Uploader implementa un sistema de envío de archivos optimizado (velocidad y sencillez).
  • UUID genera identificadores únicos universalmente.
  • Zipper permite comprimir archivos y directorios localmente.
Todos ellos ofrecen una API accesible con Javascript desde cualquier página web. Hay una guía de ejemplo.

24 diciembre, 2008

Activar Firebug 1.2 antes de usar console

Si te encuentras con el error ReferenceError: console is not defined es porque la nueva versión de Firebug exige que se active primero para hacerla disponible (con window.loadFirebugConsole()). Pretenden con ello que el código de activación incluya la definición de un objeto console para cuando Firebug no esté disponible y que no genere errores en los navegadores:

if (window['loadFirebugConsole']) {
 window.loadFirebugConsole();
} else {
 if (!window['console']) {
  window.console = { info:function(){}, log:function(){}, warn:function(){}, error:function(){} };
 }
}
En codecouch.com via Simon Willison.

18 diciembre, 2008

FireUnit

Se trata de un plugin para la extensión Firebug orientado a pruebas unitarias de código javascript. Con él se pueden realizar la típicas pruebas:


// Comprobación simple true/false
fireunit.ok( true, "Voy a pasar el test!" );
fireunit.ok( false, "Voy a fallar el test!" );

// Comparar dos cadenas
// Muestra la diferencia si son diferentes
fireunit.compare(
  "The lazy fox jumped over the log.",
  "The lazy brown fox jumped the log.",
  "Are these two strings the same?"
);

// Compara una cadena con una expresión regular
fireunit.reCompare(
  /The .* fox jumped the log./,
  "The lazy brown fox jumped the log.",
  "Compare a string using a RegExp."
);

// Muestra los resultados
fireunit.testDone();


Además permite simular eventos nativos del navegador:
// You can also simulate browser events
var input = document.getElementsByTagName("input")[0];
fireunit.mouseDown( input );
fireunit.click( input );
fireunit.focus( input );
fireunit.key( input, "a" );
O ejecutar varios tests:
fireunit.runTests("test2.html", "test3.html");
// Ubicar al final de cada archivo de prueba para continuar
fireunit.testDone();
Es el último trabajo del equipo de Firebug, potenciado por la fundación Mozilla y el trabajo de John Resig, que es el que ha publicado el trabajo.

17 diciembre, 2008

El navegador como gestor de la identidad del usuario

Si bien es cierto que OpenID ha nacido con la intención de simplificar la gestión de cuentas con las que un usuario de Internet tiene que lidiar para disfrutar de los servicios que encuentra on-line, su adopción por parte del usuario medio es más bien inexistente.

Sin duda, usar URLs en lugar de la tradicional dirección de email no ha ayudado mucho, aunque el remedio ya está en camino.

Planteándose la situación del usuario, David Recordon (vaya nombrecito) plantea la idea de que sea el navegador el que pida usuario y contraseña al iniciarse para abrir una sesión válida para aquellos sitios que acepten OpenID como método de autenticación. De esa forma, durante su uso, el navegador nos autenticará automaticamente en los sitios que indiquemos, preguntándonos en otros, y ayudándonos a registrarnos con nuestro OpenID.

Hace unas semanas hubo una intensa discusión en la comunidad OpenID sobre como mejorar la usabilidad del estándar, pero es indiscutible que hacer que el navegador gestione las cuentas, no sólo es más lógico, sino que además tiene que ser más seguro.

Extensiones como Sxipper, OpenID seatbelt y, sobre todo, OpenID para el navegador Flock (parte del proyecto IDIB) pueden dar ideas sobre cómo implementar ese soporte. David sugiere que sea Google con su proyecto Gears quien está mejor situado para ofrecer esta funcionalidad en los principales navegadores sin esperar a que la implementen nativamente. Sin duda se trata de una genial idea que beneficiaría también a Google.

13 diciembre, 2008

YQL es Yahoo! Query Language

Hace unos meses, Yahoo! lanzó Pipes, una herramienta que permitía agregar, manipular y mezclar contenido de distintas fuentes de la web. Por ejemplo, combinar varias fuentes RSS en una, ordenarlas, filtrarlas y, finalmente, traducirlas o, como expliqué en un artículo reciente, partir de una fuente de datos con direcciones para mostrar un mapa poblado con dichos datos.

Sin embargo, a pesar de la potencia de la herramienta, muchos usuarios avanzados han preferido otros métodos para realizar dichas acciones debido a que la interfície gráfica que debería resultar atractiva para muchos más usuarios nos parece demasiado ineficiente para quienes estamos acostumbrados al texto y a las consolas.

Por ello, Yahoo! acaba de lanzar YQL, que es un lenguaje muy similar al conocido SQL pero cambiando las tablas por URLs con fuentes de información. Además, para acceder a información personal, usa el estándar oAuth en lugar de solicitar contraseñas y generar con ello problemas de seguridad y confianza (oAuth es un estándar que permite acceder a información de una cuenta de un sitio determinado, como los mensajes de GMail, pero de forma que es el sitio que los contiene el que solicita permiso al usuario de forma que los datos de acceso nunca llegan al solicitante aunque sí la información deseada si se le da permiso).

Es posible probarla en esta consola on-line. En cualquier caso, si los datos son accesibles directamente y no requieren autenticación, es posible acceder a la funcionalidad de YQL a través de la URL http://query.yahooapis.com/v1/public/yql?, ya que permite obtener un resultado en formato JSON-P (accesible desde Javascript) a partir de una entrada siguiendo el estándar REST (parámetros en la URL). Por ejemplo, para obtener los últimos 3 artículos de la fuente Atom de este blog como JSON y envolverlos en una llamada a la función procesar:
http://query.yahooapis.com/v1/public/yql?q=select title from rss where url="http://feeds.feedburner.com/digitta" limit 3&format=json&callback=procesar

Otro ejemplos:

Las tablas (o fuentes de datos accesibles) predefinidas actualmente son:

atom, csv, feed, flickr.photos.exif, flickr.photos.info, flickr.photos.interestingness, flickr.photos.recent, flickr.photos.search, flickr.places, flickr.places.info, geo.places, geo.places.ancestors, geo.places.belongtos, geo.places.children, geo.places.neighbors, geo.places.parent, geo.places.siblings, geo.placetypes, gnip.activity, html, json, local.search, mybloglog.community.find, mybloglog.member, mybloglog.member.contacts, mybloglog.member.newwithcontacts, mybloglog.member.newwithme, mybloglog.members.find, mybloglog.stats.find, rss, search.images, search.news, search.web, social.connections, social.contacts, social.presence, social.profile, social.updates, upcoming.category, upcoming.country, upcoming.events, upcoming.events.bestinplace, upcoming.groups, upcoming.metro, upcoming.state, upcoming.venue, weather.forecast, xml, yahoo.identity
Fuente: Ajaxian.

09 diciembre, 2008

Native Client

Traduciendo del artículo del blog de Google:

Los PCs modernos puedes ejecutar miles de millones de instrucciones por segundo, pero las aplicaciones web de hoy día sólo pueden acceder a una pequeña fracción de esa potencia. Si los desarrolladores web pudiesen usar toda esa potencia, imagina las experiencias vivas y dinámicas que podrían crearse. En Google siempre estamos intentando hacer que la web sea una plataforma mejor. Por eso estamos trabajando en Native Client (NaCl), una tecnología destinada a dar a los desarrolladores web toda la potencia de la CPU de los clientes al mismo tiempo que se mantiene la neutralidad del navegador, la portabilidad entre sistemas operativos y la seguridad que la gente espera de las aplicaciones web. Hoy, estamos compartiendo nuestra tecnología con las comunidades de seguridad y de investigación con la esperanza de que nos ayuden a hacer esta tecnología más útil y más segura.
En definitiva, la potencia está dejando de ser un problema para las aplicaciones web. De hecho, si esta tecnología tiene éxito, estará atacando directamente a Microsoft .Net y a Sun Java, convirtiéndose en la forma más atractiva para desplegar aplicaciones y, de paso, acelerando la transición hacia el navegador como sistema operativo. Aunque también es cierto que esto implica saltarse el uso de Javascript como forma estándar de ejecutar código en el cliente, tal y como acertadamente les contestan en el primer comentario. Algo parecido a lo que ya pasó al publicarse el Google Web Toolkit. Y en cualquier caso, esto empieza a recordar un poco a las odiosas ActiveX de Microsoft.

Native Client. La guía de inicio usa Python como lenguaje a compilar. Paper PDF en el que se detalla la tecnología.

08 diciembre, 2008

Un servidor web distribuido entre las máquinas de los visitantes

En el blog de Joose publican hoy un interesante proyecto. Básicamente, aprovecha la capacidad de proceso de los navegadores de los visitantes a la página para servir información a otros visitantes, de forma que una aplicación de Google App Engine actúa como intermediaria en lugar de como servidora de recursos.

Funcionamiento

  • Cuando un usuario realiza una petición de una página del site
  • ... la petición se gestiona por una aplicación de Google App Engine
  • ... que pone la petición en una cola
  • Mientras tanto en otro equipo que ejecuta el servidor de aplicaciones Javascript dentro de un Worker de Google Gears (recuerda el artículo reciente sobre concurrencia) dentro del navegador
  • ... un cliente Comet mantiene una conexión pseudo-permanente con la aplicación de Google App Engine
  • ... busca en la cola de peticiones y empieza a procesarla
  • ... cuando ha terminado, le envía la respuesta a la aplicación de Google App Engine
  • ... la que inmediatamente envía la petición de vuelta al cliente que originó la petición en un primer momento.

Ventajas

  • Las peticiones de recursos al servidor se reducen porque cada cliente puede compartir parte de sus propios recursos con el resto de clientes.
  • Funciona con Javascript
  • Permite una integración transparente entre cliente y servidor.

Inconvenientes

  • Cada servidor de aplicaciones se ejecuta sin ningún tipo de seguridad
  • Por razones de seguridad, la respuesta del servidor de aplicaciones debe ser JSON. No puede ser HTML puro, porque cualquier cliente no autenticado podría inyectar scripts maliciosos en el flujo de datos.
  • Google App Engine desgraciamente no provee una buena forma de implementar aplicaciones de estilo Comet con peticiones prolongadas porque tienen reglas muy estrictas respecto al tiempo de espera (timeout) de las peticiones.
  • El servidor web incorporado en el SDK de Google App Engine no es multi-hilo. Por tanto, la aplicación no puede ser comprobada (fácilmente) con el SDK sino que debe ser desplegada en el sistema de producción.
  • La implementación es muy muy conceptual en el sentido de hacer las cosas más simples que funcionen, sin comprobación de errores ni de condiciones de carrera (race condition) respecto a la cola de peticiones.
  • No hay ninguna forma incluida para persistir datos en la demo actual. En cualquier caso, las aplicaciones podrían usar cualquier tipo de servicio web que esté accesible via JavaScript.
  • Actualmente no hay forma de leer o escribir cabeceras HTTP desde las aplicaciones.


Demo de cliente. Se trata de un simple contador que sólo funcionará si se ha iniciado un servidor desde el iframe incorporado en el artículo del autor, hay otro visitante ejecutando dicho servidor o se tiene abierta la demo del servidor. Aquí se puede ver el código del servidor.

06 diciembre, 2008

¿En tu servidor o en mi cliente?

John Resig ha estado echando un vistazo a Pyjamas, una librería que traduce código Python a Javascript para que pueda ser ejecutado en el navegador, de forma que un programador Python puede escribir aplicaciones web sin salirse de su lenguaje. Esta abstracción, que puede tener ciertas ventajas en apariencia, conlleva que el programador pierde la posibilidad de optimizar y depurar su código en el cliente, además de ignorar las posibilidades que Javascript ofrece para optimizar la experiencia del visitante en el navegador. Efectivamente, tanto Resig como otros discrepan sobre lo adecuado de estas soluciones.

Esto mismo es lo que hace GWT (Google Web Toolkit) con Java, Objective-J con Objective-C o, tal y como publica hoy Andrés Nieto, Harmony con PHP.

Sin duda, las mejoras en productividad de centrarse en uno de los lados (el servidor) e ignorar el otro, pueden ser importantes, pero todo depende del resultado que se quiera obtener, y perfeccionar la interfície que el usuario va a encontrarse debe formar parte de cualquier proyecto profesional.

Como todo código generado automáticamente, el generado por estas herramientas será relativamente ineficiente, aunque cuentan con la ventaja de las mejoras de rendimiento de los nuevos motores Javascript (V8, TraceMonkey o Presto).

En cualquier caso, yo optaría por el ideal para una aplicación web: que el grueso del código se ejecute en el navegador (Javascript) y se deje el resto (almacenar los datos y cuidar quién y cómo se accede a estos) al servidor usando métodos sencillos de comunicación como son JSON (datos), HTTP (canal) y REST o Comet (método). Y en todo caso, le veo mucho más sentido a llevar Javascript al lado del servidor (Helma, Jaxer, MooServer, etc.) para escribir esas pocas funciones que extender los otros lenguajes al cliente usando un sistema tan poco natural como lo son las abstracciones. Addendum: Más reacciones sobre este tema en Ajaxian.

Un servidor web gestionado por Amazon

Desde que Amazon inició su línea de servicios Amazon Web Services, se ha hablado mucho de algunos de sus servicios como su alojamiento S3 o sus máquinas virtuales EC2 y muy poco de otros como su novedosa base de datos SimpleDB.

Pero esta clase de servicios ofrecidos por sus datacenters y por tanto con una elevada capacidad y rendimientos, no sólo deben ser aprovechados por empresas. En muchas ocasiones tenemos contratado un alojamiento web para los proyectos que vamos realizando y, EC2, a pesar de ser caro (72$ o 57€ al cambio de hoy, más unos pocos céntimos más por el ancho de banda), es el servicio más flexible, fiable y potente al que se puede aspirar y que, por tanto, merece la pena considerar.

En este artículo, un desarrollador ofrece paso a paso cómo montar un servidor propio con la pila LAMP (Linux-Apache-MySQL-PHP) preparada para soportar cualquier tipo de carga y cómo realizar copias de seguridad automatizadas. En este caso, su objetivo es optimizar Drupal, los pasos serían similares para cualquier otro tipo de software como los sistemas de publicación Wordpress o de foros phpBB.

05 diciembre, 2008

Concurrencia en el navegador

Este miércoles, Andrea Giammarchi publicaba un método que se aprovechaba de las clausuras para crear scripts que no se bloqueen al cargar la página. Lo cierto es que el uso de las librerías y del lenguaje Javascript en general ha aumentado lo suficiente como para que se estén alcanzando todos los límites que durante años han sido suficientes. Las aplicaciones web no dejan de crecer en funcionalidad y prueba de que el rendimiento empieza a resentirse es la aparición de nuevos motores mucho más optimizados que están dejando sin argumentos a quienes decían despectivamente que "ese es un lenguaje de juguete".

Google que ha hecho un excelente trabajo con Gears para suplir las carencias de los navegadores, ya incluyó su WorkersPool con la idea de lanzar hilos de código que se ejecuten en segundo plano de forma que no bloqueen el navegador y ofrezcan al visitante una sensación de lentitud no deseada.

Hoy es notícia que la próxima versión de Firefox 3.1 incluirá una nueva especificación (parte 1, parte 2) acordada con Apple (Safari) y Google (que tendrá que variar la de Gears) que facilitará mucho la creación de aplicaciones web receptivas:

var worker = new Worker("workerScript.js");

Tal y como se explica aquí, ese archivo workerScript.js podrá hacer prácticamente cualquier cosa, incluyendo peticiones Ajax XMLHttpRequest, importar scripts adicionales con importScripts, lanzar otros workers, establecer intervalos o tiempos de espera, y pasar mensajes entre ellos con JSON.

El siguiente ejemplo muestra el cálculo de la función de Fibonacci mediante un hilo de forma que no bloquea la página que está visualizando el visitante y que es la que espera el resultado final:

fibonacci.js


var results = [];

function resultReceiver(event) {
  results.push(parseInt(event.data));
  if (results.length == 2) {
    postMessage(results[0] + results[1]);
  }
}

function errorReceiver(event) {
  throw event.data;
}

onmessage = function(event) {
  var n = parseInt(event.data);

  if (n == 0 || n == 1) {
    postMessage(n);
    return;
  }

  for (var i = 1; i <= 2; i++) {
    var worker = new Worker("fibonacci.js");
    worker.onmessage = resultReceiver;
    worker.onerror = errorReceiver;
    worker.postMessage(n - i);
  }
 }

HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <title>Test threads fibonacci</title>
  <body>

  <div id="result"></div>

  <script language="javascript">

    var worker = new Worker("fibonacci.js");

    worker.onmessage = function(event) {
      document.getElementById("result").textContent = event.data;
      dump("Got: " + event.data + "\n");
    };

    worker.onerror = function(event) {
      dump("Worker error: " + event.data + "\n");
      throw event.data;
    };

    worker.postMessage("5");

  </script>
  </body>
</html>

MooTools sin Sizzle

Una breve reseña al respecto del movimiento que Sizzle, el motor de selectores CSS creada por John Resig de jQuery, está generando en los equipos de desarrollo del resto de librerías.

Resig ha propuesto que todos adopten su código para unificar criterios, optimizar más si cabe este fenomenal código y mandar un mensaje a los fabricantes de navegadores y a los grupos de estandarización para que intenten también mejorar el rendimiento de todas las librerías. A la llamada han respondido positivamente jQuery (era evidente puesto que es del mismo autor), Prototype, Dojo y YUI, pero la discusión del equipo de MooTools, tras plantearse los pros y los contras y los argumentos de Resig, han decidido finalmente mantenerse al margen y continuar con su motor de selectores actual.

MooTools ha preferido tener libertad de modificar toda su base de código antes que adoptar lo que parece conformarse como un estándar de facto en el resto de librerías, aún teniendo el riesgo de tener que estar innovando continuamente para hacer frente a las optimizaciones que todos los demás hagan a Sizzle. El tiempo dirá si se equivocan o aciertan...

Addendum: Valerio Proietti de MooTools justifica en este post la decisión.

02 diciembre, 2008

Con Dabble DB se crean aplicaciones en minutos

Con tantas opciones a la hora de desarrollar una aplicación web (Ruby on Rails, AppJet, Google App Engine, Amazon EC2, ...) al final he dejado un poco de lado las "otras opciones".

Sitios más orientados a la información como DabbleDB, Zoho Creator o JotSpot (ahora integrado en Google Apps) suponen una opción atractiva a la hora de crear una aplicación con varias tablas que pueden llegar a un grado de sofisticación elevado.

El siguiente vídeo (sacado de aquí) muestra las posibilidades de este tipo de herramientas.

Últimos links en indiza.com