04 junio, 2009

El proyecto Vice-versa

He traducido la introducción del Proyecto Vice-versa presentado en este post de Andrea Giammarchi. Se trata de una librería que nace con la idea de aproximar las implementaciones de las características JavaScript disponibles desde cada navegador.

El proyecto Vice-versa


Cada navegador tiene alguna característica deseable: puede ser su rendimiento, puede ser algo que "aún no se ha estandarizado", puede ser una característica preparada para ECMAScript 5. El proyecto Vice-versa pretende traer lo bueno de cada navegador a un único archivo JavaScript ligero y que valga para todos los navegadores.

Filosofía


Array.forEach(document.all, function(node, i, all){
    // proyecto vice-versa
});
Como un Ninja JavaScript tengo que tratar diariamente con centenares de problemas diferentes a causa de "esta o aquella" implementación por parte de un navegador. La web está llena de librerías pero a menudo lo que necesitamos hacer requiere usar el navegador "tal cual" y estas librerías puede ayudar o simplemente pueden hacer más lentas las aplicaciones a causa de sobrecargas innecesarias sobre tareas simples o comunes. Estudiando el DOM, que es caótico, a menudo "viajo" entre los sitios de MDC y de MSDN para resolver un problema específico que puede causar muchos dolores de cabeza a causa de "alguna" implementación del estándar W3C que alguien ha olvidado realizar. Al mismo tiempo, teniendo en cuenta que el navegador más usado es el que tiene el motor de JavaScript más lento, siempre intento encontrar soluciones que puedan completar una tarea sin afectar al rendimiento. En la mayoría de los casos, he notado que, ya que otros navegadores son más rápidos y más potentes, tiene sentido traer funcionalidades no estándar a esos navegadores en lugar de implementar, cuando sea posible, una funcionalidad omitida en Internet Explorer. Como ejemplo básico, para convertir un documento XML en una cadena, nos gustaría usar una instancia de XMLSerializer, pero ¿qué problema hay con el atajo del atributo xml de Microsoft?

// al estilo de otros navegadores (estándar)
var xmls = new XMLSerializer;
var string = xmls.serializeToString(myXMLDocument);

// al estilo de Internet Explorer (no estándar)
var string = myXMLDocument.xml;
Es más, document.evaluate es una característica muy buena, pero la llamada más común a esta función es la siguiente:

var xpresult = document.evaluate(XPathSelector, myXMLDocument, null, 0 /* as ANY_TYPE */, null);

// En internet explorer hay una función ligeramente diferente: selectNodes
var xpresult = myXMLDocument.selectNodes(XPathSelector);
La diferencia principal es el número de caracteres necesarios para llamar al método estándar en lugar de el de IE, aunque el resultado es exactamente el mismo durante las iteraciones (donde IE usa nextNode, el resto usa iterateNext). De nuevo, si estamos en Internet Explorer podemos confiar en la propiedad más fea que hayamos visto nunca desde la primera implementación de JScript sonbre el DOM: document.all. Ahora, ¿por qué demonios nos encanta la "miniaturización" de YUICompressor más gzip pero preferimos una sintaxis sin sentido como document.getElementsByTagName("*") en lugar de document.all ?

La lista podría seguir con execScript para evaluar código en el ámbito global (relacionado con tiempo de ejecución y con Ajax) y con Object.defineProperty, pero al mismo tiempo tenemos carencias con Array.prototype desde hace una eternidad, algo relativamente aburrido ya que el prototipo del constructor global debe permanecer "intocable" por razones de compatibilidad ... Ya es hora de comprender que nadie hace un bucle for in sobre listas o colecciones, así que Array.prototype ha de ser estandarizado, no hay "puede ser" o "quizá", especialmente ahora que se ha implementado como estándar en ECMAScript 5. Como resumen, estos son conceptos dentro del proyecto vice-versa: especialmente si estos comportamientos pudieran enlentecer el rendimiento general de las aplicaciones, o si estos comportamientos no son estándares.

Características vice-versa provenientes de Internet Explorer


  • Object.defineProperty (IE 8 o superior)
  • document.all, como atajo a document.getElementsByTagName("*")
  • document.createElement con soporte html para cada navegador (a veces simplifica las cosas p.e. document.createElement('<em class="test"></em>'))
  • HTMLElement.attachEvent y detachEvent
  • objeto global window.event poblado via attachEvent con las propiedades cancelBubble y returnValue
  • HTMLElement.outerHTML con set y get (la forma más simple de leer un elemento del DOM como una cadena)
  • HTMLElement.innerText con set y get (la forma más rápida en IE de insertar un nodo de texto)
  • HTMLElement.outerText con set y get (la forma más rápida en IE de reemplazar un nodo genérico por uno de texto)
  • execScript para evaluar en un ámbito global cualquier tipo de cadena (sin soporte a un segundo argumento)
  • XPath selectNodes y nextNode via documentos XML
  • propiedad xml, sólo get, para recuperar una cadena de un XMLDocument/XMLNode
  • insertAdjacentElement, insertAdjacentHTML, y insertAdjacentText, la forma más rápida de poner algo antes de un nodo, como firstChild, como lastOne, o tras el mismo nodo

Características vice-versa principalmente para Internet Explorer


  • Array.slice, para trocear todo sobre una colección genérica (compatible con DOM)
  • Array.forEach, para recorrer una colección genérica via callback (compatible con DOM)
  • Array.prototype, actualizado a la última revisión de Mozilla/FireFox (sin la especificación completa, versión enfocada en rendimiento)
  • XMLHttpRequest, para el antiguo IE6 (desfasado, será eliminado tan pronto como se pueda, pero debemos esperar primero hasta el final de este navegador)
  • setInterval y setTimeout con argumentos extra como los demás

Características vice-versa de ECMAScript 5


  • Object.getPrototypeOf, para recuperar el prototipo heredado por un objeto genérico
  • Object.keys, compatible (incluyendo toString), para recuperar un Array de claves a partir de un objeto
  • Object.create, compatible (incluyendo toString), para crear una nueva instancia a partir de otro objeto
  • Array.isArray, para conocer si un objeto genérico es un Array
  • String.prototype.trim, una implementación rápida de recorte para cada cadena
  • Function.prototype.bind, un método para asegurar el ámbito this en una llamada a función

Características extra en vice-versa


  • document.query, librería esencial de selectores para obtenere resultados genéricos mediante consultas comunes de tipo dolar (función $)
  • Object.forIn, para recorrer una instancia genérica sin considerar al prototipo heredado y sin olvidar las propiedades predefinidas (toString, valueOf, etc)

Metas de vice-versa


Pronto llegarán más funcionalidades, esperando mantener por debajo de 10KB de tamaño total minificado y comprimido (actualmente está en 4KB). Esta es sólo una implementación parcial de mi idea original. Las librerías de terceras partes serán bienvenidas, y los colaboradores de otros equipos de librerías serán más que bienvenidos. La idea principal es crear un híbrido completo del escenario JavaScript haciendo que los rendimientos sean similares en cada navegador y ofreciendo una estructura de bajo nivel para construir librerías complejas, aplicaciones, ... respetando donde sea posible a Internet Explorer, y trayendo sus características dentro de otros navegadores rápidos y potentes. ¿Estoy loco?

Publicar un comentario en la entrada

Últimos links en indiza.com