Angular y rendimiento

Últimamente estoy haciendo muchos proyectos utilizando Angular, bien sea usando solo Angular + Bootstrap o Ionic que está basado en él.

Me suele gustar buscar información sobre buenas prácticas y mejorar el rendimiento de las aplicaciones hechas con dicha tecnología y hoy he encontrado un artículo en el cual con una sola línea se mejora de manera notable el rendimiento en producción de una aplicación hecha con Angular.

La línea en cuestión es la siguiente:

$compileProvider.debugInfoEnabled(false);

Concretamente su uso completo sería el siguiente:

myApp.config(['$compileProvider', function ($compileProvider) {
  $compileProvider.debugInfoEnabled(false);
}]);

Lo he probado en dos proyectos que tengo hechos con Angular y en uno con Ionic, y en los de Angular la mejora ha sido bastante buena, las páginas renderizan mucho más rápido. En Ionic he notado que la fluidez de la app al cambiar de vista mejoraba de manera considerable.

La recomendación de todas formas es que lo actives cuando la aplicación esté en producción así que yo la he usado de la siguiente manera:

// Angular

myApp.config(['$compileProvider', function ($compileProvider) {
  if (document.location.host.indexOf('localhost') === -1) {
    $compileProvider.debugInfoEnabled(false);
  }
}]);

// Ionic

myApp.config(['$compileProvider', function ($compileProvider) {
  if (window.cordova) {
    $compileProvider.debugInfoEnabled(false);
  }
}]);

Aquí dejo la referencia al artículo en cuestión y alguno más que da consejos para mejorar el rendimiento de aplicaciones hechas con Angular:

https://medium.com/swlh/improving-angular-performance-with-1-line-of-code-a1fb814a6476#.ov0lfveqz
http://maxmautner.com/post/135816438020/11-huge-ionic-performance-tips
http://julienrenaux.fr/2015/08/24/ultimate-angularjs-and-ionic-performance-cheat-sheet/

Cifrado en Javascript compatible con openssl_encrypt de PHP

Tengo un proyecto entre manos en el cual necesito cifrar una cadena de texto desde Javascript y que esta se descifre en un servicio que está hecho en PHP.

Una búsqueda por Internet me ha dado las siguientes librerías:

  • https://github.com/mdp/gibberish-aes
  • https://github.com/bitwiseshiftleft/sjcl
  • https://github.com/brainfoolong/cryptojs-aes-php
  • https://code.google.com/p/crypto-js/

Con ninguna de ellas he conseguido que metiendo yo el iv como parámetro sea equivalente a la siguiente llamada en php:

openssl_encrypt('Hola', 'aes-256-cbc', 'My32charPasswordAndInitVectorStr', false, '1234567890123456');

Después de más búsquedas, he encontrado la solución:  node-crypto + browserify

La idea es usar la librería crypto de node en el navegador mediante la herramienta browserify.
Para ello instalo browserify:

npm install -g browserify

Instalo crypto:

npm install crypto

Creo el fichero cifrar.js con el siguiente contenido:

var crypto = require('crypto');

var Crypto = {};

Crypto.encrypt = function (plain_text, encryptionMethod, secret, iv) {

      var encryptor = crypto.createCipheriv(encryptionMethod, secret, iv);

      encryptor.setEncoding('base64');
      encryptor.write(plain_text);
      encryptor.end();

      return encryptor.read();
};

Crypto.decrypt = function (encryptedMessage, encryptionMethod, secret, iv) {
      var decryptor = crypto.createDecipheriv(encryptionMethod, secret, iv);
      return decryptor.update(encryptedMessage, 'base64', 'utf8') + decryptor.final('utf8');
};

window.Crypto = Crypto;

Y por último utilizo browserify para crear el fichero que incluiré en el proyecto:

browserify cifrar.js -o crypto.js

Y la llamada equivalente en Javascript sería la siguiente:

Crypto.encrypt('Hola', 'AES-256-CBC', 'My32charPasswordAndInitVectorStr', '1234567890123456');

SuperSefile

En el último proyecto que he realizado por encargo, he tenido que utilizar una serie de herramientas que me han parecido interesantes y que comparto aquí por si alguien las necesita para otros proyectos.

Es una app de fotografía, en la cual sacas una foto, la puedes firmar, y después puedes componer la firma con la foto e incluso añadir algún que otro texto incluyendo emojis.

Para empezar decidí no usar ningún framework de javascript, ya que quería que la app fuera lo más ligera posible, si que es cierto que he tenido que sacrificar un poco la legibilidad del código de la misma, pero siendo estricto en la nomenclatura de las funciones he conseguido estructurar bien el código y que no fuera muy difícil su depuración.

El único sacrificio que he tenido que hacer ha sido meter jQuery, ya que la librería que he usado para la firma era un plugin de jQuery, si bien es cierto que lo usa para un par de accesos y eventos, desvilcularla de jQuery o usar una librería más liviana, tipo Zepto.js, no era mi prioridad y podría meterme en jardines que realmente no quería pisar.

Para la firma entonces usé el plugin de jQuery, jSignature. Básicamente lo que hace es crear un canvas en el cual se puede realizar la firma, el algoritmo que usa es bastante bueno y tienen un rendimiento aceptable incluso en Android 4.0.4.

Para la composición de la firma y la foto use una librería con muchas más funcionalidades de las que necesitaba pero con vistas a una posible evolución de la app. La librería es Fabric.js. Como pone en su web es un modelo de datos intercativo que proporciona una API para realizar operaciones sobre un objeto de tipo canvas. La verdad es que es muy completa y tiene un montón de ejemplos a parir de los que empezar a trabajar.

Para finalizar me hacía falta un colorPicker y ya que tenía que usar jQuery busqué uno que se amoldara a mis necesidades y que fuera un plugin de jQuery: Spectrum. Al igual que Fabric.js, este plugin tiene más funcionalidades de las que necesito, pero lo elegí por poder implementar las mismas en una futura evolución de la app.

Por lo demás el resultado lo podéis ver aquí:

https://play.google.com/store/apps/details?id=com.javray.SuperSelfie
https://itunes.apple.com/es/app/superselfie/id957281514

Compartir con Whatsapp en Phonegap (iOS y Android)

Una de las funcionalidades que últimamente me están demandado para las aplicaciones es la de poder compartir un texto o un foto por Whatsapp.

Al ser un producto de terceros y no tener una API pública, mi respuesta siempre era la de que no era posible. Hasta ahora, o hasta hace relativamente poco tiempo.

Buscando si era posible, me encontré con el siguiente FAQ la propia aplicación:

http://www.whatsapp.com/faq/en/iphone/23559013

Esto ya me dio una pista de hacia dónde orientar mis pruebas de cómo implementarlo.

La parte fácil es la de compartir texto, ya que usando el esquema de URL whatsapp:// se puede usar en ambas plataformas y es tan sencillo como poner un enlace o abrir una página:

<a href="whatsapp://send?text=Hello%2C%20World!">Whatsapp></a>
window.open('whatsapp://send?text=Hello%2C%20World!');

Para las imágenes las cosas se complica y tendremos que usar métodos diferentes según la plataforma.

iOS

Aquí vamos a usar la API de Document Iteration, básicamente es una API que nos permite sacar las aplicaciones que pueden abrir un tipo de documento, como sucede con Dropbox cuando te bajas un archivo y te da la opción de editarlo con aplicaciones externas que tengas instaladas.

Para usar esta API nos instalaremos el siguiente plugin de Phonegap:

https://github.com/phonegap/phonegap-plugins/tree/master/iOS/ExternalFileUtil 

Este plugin lo único que hace es abrir un cuadro con las aplicaciones compatibles con el tipo de documento que queremos compartir. Yo he modificado un par de cosas ya que el plugin devolvía siempre una cadena vacía abriera o no el cuadro, lo cual no es muy útil ya que no permite controlar si está o no instalado el Whatsapp en el dispositivo.

La modificación es en el fichero CDVExternalFileUtil.m y hay que cambiar la línea 64, de esto:

[controller presentOpenInMenuFromRect:rect inView:cont.view animated:YES];

a esto:

BOOL result = [controller presentOpenInMenuFromRect:rect inView:cont.view animated:YES];

Y la línea 66, de esto:

pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @""];

a esto:

pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: (result ? @"YES" : @"NO")];

Una vez hechos esos cambios la manera de usar el plugin es la siguiente:

ExternalFileUtil.openWith('http://example.com/imagen.wai', "net.whatsapp.image", 
                function(result) { 
                    if (result == 'NO') {
                        // No está instalado el Whatsapp
                    }
                }
            );

El fichero imagen.wai es un JPG pero renombrado a .wai que es la extensión que usa el Whatsapp para saber que es una imagen. Para vídeos es .wam y para sonidos .waa.

Android

Aquí lo tenemos algo más fácil ya que mediante Intents podemos compartir una imagen.

Usaremos el siguiente plugin para poder lanzar Intents:

https://github.com/phonegap/phonegap-plugins/tree/master/Android/WebIntent

También es necesario modificarlo un poco ya que no tiene implementada la opción de lanzar directamente un Intent asociado a un paquete.

Por tanto los cambios a realizar son en el fichero  WebIntent.java, en la línea 54, añadir debajo la siguiente línea:

String pack = obj.has("package") ? obj.getString("package") : null;

En la línea 70, cambiar esto:

startActivity(obj.getString("action"), uri, type, extrasMap);

por esto:

startActivity(obj.getString("action"), uri, type, pack, extrasMap);

En la línea 158, añadir debajo lo siguiente:

if (pack != null) {
  i.setPackage(pack);
}

El uso sería el siguiente:

var extras = {};
                            extras[window.plugins.webintent.EXTRA_STREAM] = imagen_b64;

                            window.plugins.webintent.startActivity({ 
                                action: window.plugins.webintent.ACTION_SEND,
                                type: 'image/*', 
                                package: 'com.whatsapp',
                                extras: extras 
                                }, 
                                function() {
                                    // OK
                                }, 
                                function() {
                                    // El Whatsapp no está instalado.
                                }
                            );

La variable imagen_b64 será una imagen codificada en base64, podremos usar un fileReader si la imagen está en el dispositivo o un fileTransfer si está en un servidor.

[Editado]

Parce que lo del esquema de URL solo lo han implementado para iOS, para Android habrá que usar también el WebIntent:

var extras = {};
                            extras[window.plugins.webintent.EXTRA_TEXT] = 'Hola mundo';

                            window.plugins.webintent.startActivity({ 
                                action: window.plugins.webintent.ACTION_SEND,
                                type: 'text/plain', 
                                package: 'com.whatsapp',
                                extras: extras 
                                }, 
                                function() {
                                    // OK
                                }, 
                                function() {
                                    // El Whatsapp no está instalado.
                                }
                            );

[/Editado]

Configurando el VIM para que suba por FTP

Tanto en mi trabajo como en mis proyectos personales utilizo como editor de texto y entorno de desarrollo el vim. Me gustan los entornos livianos y que respondan con rapidez cuando escribo.

Al usar únicamente el vim, cuando tengo que subir un fichero al servidor, me apoyo un un cliente de FTP, en este caso, el Filezilla. Y claro, pierdo tiempo entre :w!, CMD + TAB y por último arrastrar el fichero.

Para ser más productivo, decidí que ya era hora de mirar la manera de poder subir un fichero directamente desde el propio vim con alguna combinación de teclas.

Me puse manos a la obra y después de un rato buscando, encontré los plugins que me harían falta para lograrlo.

El primero de ellos y el más importante fue el netrw. Este plugin permite realizar operaciones de lectura y escritura en red, es decir permite editar ficheros en remoto y subir ficheros por FTP, SFTP, SCP e incluso RSYNC.

El segundo que hace falta es el localvimrc. Este plugin permite definir una configuración especifica para cada proyecto. En mi caso lo uso para definir el comando que voy a usar para subir el fichero que estoy editando al servidor.

Una vez instalados ambos plugins, lo que hay que hacer es ir a la carpeta local donde tienes el proyecto y crear el fichero .lvimrc, dentro del cual vamos a meter un comando similar a éste:

map <leader>S :execute 'Nwrite ftp://www.javray.com//home/miproyecto/' . expand("%")

Yo he definido <leader>S para subir el fichero que estoy editando, pero se puede definir la combinación que os sea más comoda. También se pueden definir distintos comandos.

Eso sí, al usar el protocolo FTP para que no me pida la clave he tenido que usar el fichero .netrc, en el cual he definido el servidor, el login y el password. Una opción más segura sería subir el fichero por SCP y meter la clave publica de mi ordenador en el servidor.

¿Lo siguiente?

Crear un comando que me suba al repositorio el fichero, a ver si investigo un poco y os lo cuento.

Debug remoto

Estoy probando una aplicación en el iPad que básicamente es una UIWebView que accede a una página de Internet que es la que realmente tiene la aplicación.

En el navegador de escritorio todo funciona perfectamente, pero a la hora de probarlo en el iPad he detectado un comportamiento distinto y necesito saber qué es lo que pasa y por dónde va el flujo de ejecución.

Para ello existen muchas soluciones, bastante complicadas desde mi punto de vista, que pueden servir para ver qué es lo que está pasando como por ejemplo: Enabling Remote Debugging via Private APIs in Mobile Safari.

Pero no me acaba de convencer, así que he optado por otra solución, que leí hace un tiempo y no recuerdo dónde.

La idea es redefinir el objeto console para que realice una petición a un servidor enviando el contenido con el que se le ha invocado, algo así como un log remoto.

Para ello con el siguiente código se puede conseguir:

(function(window, undefined) {
    var console_old = window.console,
        console = {};

    console.log = function() {
        var xhr = new XMLHttpRequest();
        
        xhr.open('POST', '/console.php', true);
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.send('log=' + JSON.stringify(arguments[0]));

        console_old.log(arguments[0]);
    };

    console.info = console.log;
    console.warn = console.log;

    window.console = console;

})(window);

El código en el servidor sería el siguiente:

 exec("echo '".$_POST['log']."' >> /tmp/console.log");    

Con todo lo anterior ya podemos poner debugs por el código y ver en tiempo real por dónde está pasando la aplicación y qué problemas tiene.

Ni que decir tiene que aplicar esto a un desarrollo web o aplicación nos puede servir para poder saber qué tipos de errores les da a los usuarios, eso sí habría que mandar un poquito más de información para poder resolver incidencias que les ocurran.

Github

Hace un tiempo que me hice una cuenta en Github para aprender a utilizar git, ya que me parece una mejor opción que SVN. De momento lo he usado bastante poco, he subido tres proyectos: dos de ellos muy sencillos y un tercero algo más complejo.

Empezando por el más complejo, Galert, es un aplicación para Android hecha en python usando SL4A, la tengo publicada en Google Play, como es gratuita y es más un experimento que otra cosa, he decidido liberar lo que he hecho:

https://github.com/javray/Galert

La siguiente es un sencillo script en PHP que coge un RSS y lo transforma en comandos SHELL para que se vea con colores en el terminal:

https://github.com/javray/RSS-Colorize

Y la última, es una única página que contiene HTML y Javascript, la cual sirve para realizar un sorteo entre varios participantes. La idea es que tienes los participantes en un fichero de texto, arrastras éste a la aplicación, eliges cuántos ganadores quieres y le das a sortear:

https://github.com/javray/Sorteo

Espero seguir publicando más aplicaciones que se me vayan ocurriendo, ya que es bueno compartir el código para aprender.

Números y rendimiento

Sigo buscando que mis aplicaciones hechas en javascript se ejecuten más rápido, para ello recientemente he descubierto unos trucos para para poder acelerar la conversión de strings en números.

Para ello, en vez de usar parseInt y parseFloat que son increiblemente lentos, uso el operador unario ‘+’:

//var numero = parseInt('12');
var numero = +('12');

//var numero = parseFloat('12.1');
var numero = +('12.1');

La razón de que el operador uniario sea más rápido es que éste no realiza una comprobación de los límites superiores e inferiores del número, eso sí hay que tener cuidado de que el string sea un número válido.

Referencias:

http://monkeyandcrow.com/blog/js_coercion_performance/
http://jsperf.com/parsing-vs-coercion

Expansión de objetos con variables y métodos privados

Continuando con el apasionante mundo de la creación de objetos en javascript y después de haber aprendido a usar los getters y los setters, me he puesto a definir objetos y quería que todos ellos tuvieran la función de vincularse unos con otros.

Al hacer esto me he visto repitiendo una y otra vez el mismo código para realizar esa vinculación, lo cual no es buen sintoma. Así que me he parado a pensar cómo podría hacer para crear un objeto genérico con esas propiedades para que los demás objetos, por así decirlo, hereden esas propiedades.

Me he puesto manos a la obra y lo primero que he hecho ha sido crear la definición de ese objeto genérico que va a contener, de momento, solo la funcionalidad de vincular.


var Objeto = function() {
    var self = this;

    self._binds = {};

    self.clase = {
      bind: function(v, o, f) {
        self._binds[v] || (self._binds[v] = []);
        self._binds[v].push({
          obj: o,
          func: f
        });
      }
    };

    self._bind = function() {
      self._binds['value'] && self._binds['value'].forEach(function(e) {
        e.func.apply(e.obj, [self.clase]);
      });
    };
  };

Después de tener el objeto genérico y sabiendo que no voy a instanciar ningún objeto real con él, sino que lo voy a usar para crear otro objeto el cual sí será la clase que usaré para instanciar los demás objetos, me he puesto a buscar información sobre constructores, prototipos y demás.

Al cabo de un buen rato he dado con una solución válida para mi problema, ya que yo quiero mantener ciertas variables y ciertos métodos privados; y con la información que había obtenido de mi búsqueda siempre tenía todas las variables a la disposición de la instancia que creaba.

La solución es la siguiente:

var miObjeto = function() {
    var self = this,
        _value = 0;

    // Cogemos las propiedades genéricas

    Objeto.apply(this);

    // Definimos los getters y los setters

    self.clase.__defineGetter__('value', function() {
      return _value;
    });
    self.clase.__defineSetter__('value', function(v) {
      _value = v;
      self._bind(); // Llamamos a la función de vinculación
    });

    return self.clase; // Devolvemos únicamente la clase
  }

Como los constructores en javascript son funciones y todas las funciones tienen el método call, lo que se me ha ocurrido es llamar a la función/constructor Objeto sobre miObjeto, con lo que se consigue que se definan dentro de miObjeto todas las propiedades y métodos que estaban presentes en Objeto.

Luego utilizo la otra manera de definir getters y setters, que tienen javascript, para definir las demás propiedades de miObjeto y por último devuelvo el objeto clase que contiene los métodos públicos que deseo que tenga la instancia que utilice dicha clase.

El uso de estas nuevas clases es igual que en el artículo anterior, con la diferencia de que si ahora creo, por ejemplo, un miObjeto2, no tengo que volver a implementar la funcionalidad de vincular ya que la puedo heredar de Objeto.

var miObjeto2 = function() {
    var self = this,
        _enable = 0;

    // Cogemos las propiedades genéricas

    Objeto.apply(this);

    // Definimos los getters y los setters

    self.clase.__defineGetter__('enable', function() {
      return _enable;
    });
    self.clase.__defineSetter__('enable', function(e) {
      _enable = e;
      self._bind(); // Llamamos a la función de vinculación
    });

    return self.clase; // Devolvemos únicamente la clase
  }
  var miObjetoReal = new miObjeto();
  var miObjetoReal2 = new miObjeto2();
  miObjetoReal.bind('value', miObjetoReal2, function(e) {
    (e.value != '') && (this.enable = 1) || (this.enable = 0);
  });

También a estos objetos se les podría añadir la vinculación con un elemento DOM, como en el artículo anterior, y tendríamos unos objetos con los que trabajar sin preocuparnos de las actualizaciones de la interfaz.

Referencias

http://www.webdeveloper.com/forum/showthread.php?t=243971
http://www.3site.eu/doc/
http://stackoverflow.com/questions/6039676/copying-javascript-getters-setters-to-another-prototype-object

Getters, Setters y vinculación de objetos

Recientemente he estado leyendo algunos artículos de javascript en los que se explicaban las bondades de los getters y los setters y cómo podemos utilizarlos para darles más funcionalidad a nuestras clases.

Un Ejemplo sencillo sería el siguiente:

  var MiClase = function() {
    var _value = 0;
    var clase = {
      get value() {
         return _value;
      },
      set value(v) {
         _value = v;
      },
    };
    return clase;
  };

Lo definido arriba es equivalente a esto:

  var MiClase = function() {
    this.value = 0;
  };

Pero claro, ¿para qué hacer algo más complicado si no se obtiene ningún beneficio?, la respuesta está en que al ser los getters y los setters funciones, podemos añadir más acciones dentro de estas a parte de las de devolución y asignación de variables.

Uno de los usos que se le puede dar es vincular un objeto que creemos a través de la clase con un objeto DOM, como por ejemplo una caja de texto:

  var MiClase = function(t) {
    var _value = 0,
        _obj = document.getElementBy(t);

    var clase = {
      get value() {
         return _value;
      },
      set value(v) {
         _value = v;
         _obj.value = v;
      },
    };

    _obj.addEventListener('blur', function() {
      clase.value = this.value;
    }, false);

    return clase;
  };

  var miObjeto = new MiClase('micaja');

Con el código de arriba conseguimos vincular el objeto miObjeto con la caja de texto de identificador micaja, de manera que siempre que introduzcas algo en la caja de texto se actualizará la propiedad value del objeto miObjeto y viceversa.

Podemos complicar un poco más la definición de la clase para añadir vinculación entre objetos, es decir, yo quiero vincular dos objetos a través de una propiedad de uno de ellos, de manera que cuando actualice la propiedad en el objeto origen en el objeto destino se realicen una serie de acciones. Para todo esto, la clase quedaría de la siguiente manera:

var MiClase = function(t) {
    var _value = 0,
        _obj = document.getElementBy(t),
        _binds = {};

    var clase = {
      get value() {
         return _value;
      },
      set value(v) {
         _value = v;
         _obj.value = v;
         var self = this;
         _binds['value'] && _binds['value'].forEach(function(e) {
           e.func.apply(e.obj, [self]);
         });
      },
      bind: function(v, o, f) {
        _binds[v] || (_binds[v] = []);
        _binds[v].push({
          obj: o,
          func: f
        });
      }
    };

    _obj.addEventListener('blur', function() {
      clase.value = this.value;
    }, false);

    return clase;
  };

Lo que hemos hecho ha sido añadir un objecto que contiene un array de vinculaciones, _binds, y una función bind que nos permite asociar objetos. También hemos añadido en el setter la ejecución de las funciones de vinculación que pueda tener el objeto pasando como parametro el propio objeto para que puedan interactuar con él.

Ahora el código para realizar las vinculaciones:

  var miObjeto1 = new MiClase('caja1');
  var miObjeto2 = new MiClase('caja2');

  miObjeto1.bind('value', miObjeto2, function(e) {
    this.value = e.value + '(copia)';
  });

Con el código de arriba lo que hemos hecho ha sido vincular las cajas de texto caja1 y caja2 con los objetos miObjeto1 y miObjeto2 respectivamente y después hemos vinculados los dos objetos entre sí por medio de la propiedad value de miObjeto1 de manera que cuando ésta cambie se llamará a la función de vinculación. En este ejemplo sencillo, cada vez que se cambia la propiedad value de miObjeto1 se le asigna a la propiedad value de miObjeto2 el mismo valor más el texto “(copia)”.

Dentro de la función de vinculación, this hace referencia al objeto destino, en nuestro ejemplo, miObjeto2 y el parámetro e hace referencia al objeto origen, en el ejemplo, miObjeto1.

Referencias
JavaScript getters and setters: varying approaches
Javascript getters and setters for dummies?
Working with objects