Jsrs, Javascript y las funciones lambdas

Enviado por admin el Mar, 09/11/2004 - 13:43.
Clasificado en:

Actualización Mayo 2008: jsrs es muy lento en relación con HttpRequest para hacer AJAX, pero la explicación sobre el uso de lambdas sigue siendo válida.

A mi me gustan muchos los 'gastos' y la utilidad jsrs. Esta permite hacer consultas al servidor sin necesidad de recargar la página. Claro está, existen varias otras aplicaciones que hacen lo mismo, pero esta es pequeñita y rápida.
Para que se hagan una idea, la función básica de la util es
jsrsExecute(url,callback,funcion,parametros,visibilidad)
Teniendo que:

  • url: Url de la página donde se encuentre el script, ya sea php, python, asp o lo que sea
  • callback:Función javascript que recibirá el texto de vuelta del servidor
  • funcion: Nombre de la función php, vb, pythoniana o lo que sea que recibirá los siguientes...
  • parámetros: que creen uds? Tengan cuidado, eso sí, de mandar strings, que o si no la cosa falla. Basta con hacer numero+''
  • visibilidad: facilita el debug, ya que muestra en pantalla lo que el servidor devuelve o payload

Hasta aquí, todo bien. Tuve que crear un pequeño wrapper en una clase para que la función seleccionada del Php pudiese correr sobre un objeto, pero lo que nunca pude hacer es hacer que el callback javascript pudiese ser la función de un objeto. Nada.
Revisando el código fuente, me di cuenta que cada petición que uno hace se maneja vía un objeto. El callback que uno envía pasa a ser una de sus propiedades y como javascript es un lenguaje que maneja bien los closures, todos los this que tenga la función que enviamos pasan a ser referencias del nuevo objeto.
En lo práctico

function miClase() {
    this.envio = function () {
    jsrsExecute('script.php',this.miCallback,'funcion_php')
}
this.miCallback = funcion() {
    alert(this)
}
} 

Claro, cuando corro el jsrsExecute el this.miCallback es la función dentro de miClase. El único problema es que cuando jsrs hace

 if( contextObj.callback != null){
    contextObj.callback( jsrsUnescape( contextObj.getPayload() ), contextID );
  }

Las referencias los this ya no son las de miClase, sino las de contextObj!
Como lo solucionamos?
Acabo de pillar un truco bastante simpático. El único problema es que necesitan, creo que obligatoriamente, otro objeto que maneje las referencias a los objetos que hacen las llamadas.
Por ejemplo, tengamos un manejador, que lo creamos como un 'singleton'

    var Manejador =  {
    var aRefs=new Array(),
    agregar : function (obj) {
        this.aRefs[obj.id]=obj
    },
    get : function (id) {
    return this.aRefs[id]
    }
}

Creo que pueden captar la idea. El único requisito que tienen que tener los objetos referenciados es que posean un atributo id que debe ser único.
Ahora, dentro de los objetos podremos hacer las llamadas de la siguiente manera

function miClase(id) {
     this.id=id;
    function llamar() {
        var id=this.id
        jsrsExecute(url,function(text,context) {Manejador.get(id).callback},'funcion_php'}
    }
function callback(texto,contexto) {
    alert(texto);
}
}
a=new miClase(1);
Manejador.add(a);
a.llamar

¿Cómo funciona? Todas las funciones en Javascript son closures, o sea, los valores de las variables a las cuales hacen referencia dependen del contexto. Por ejemplo, this es una variable que dependiendo de desde que objeto se llame a la función varía. Ahora bien, el detalle es que hemos creado la variable id dentro del espacio de la función llamar. Los closures buscan primero las variables en el contexto donde son ejecutadas y, despúes, en el contexto en el cual fueron creadas. En este caso, id se define de modo explícito (en este caso particular, como 1), y aunque la función se lleve a cabo dentro del contexto del objeto jsrs, el Manejador nos permitirá retomar la referencia a nuestro objeto original.
Espero que les haya servido para comprender un poquito más a ese incomprendido lenguaje llamado JavaScript.

Actualización, 15 minutos despúes: Cómo la brutalidad no puede durar tanto tiempo, me acabo de dar cuenta que es mucho más sencillo de lo que yo creía. Bastar con crear un 'alias' para this. Como en el segundo objeto no existe (ojalá), una referencia a este alias, este podrá representar al objeto con todas las de la línea.
Encontes, el código de arriba, reformulado:

function miClase(id)  {
    function llamar() {
        me=this;
        jsrsExecute(url,function(text,context) {me.callback},'funcion_php'}
    }
function callback(texto,contexto) {
    alert(this)
    }
}
a=new miClase(1);
a.llamar

Ahora sí. Mucho más simple, no? Todavía necesitamos la función lambda, pero no tenemos que pasar por la lata de llamar al Manejador.
Nos vemos!

Imagen de Jordi

Wow! muy interesante! a pesar de que dices que existen otras aplicaciones que hacen lo mismo, yo no conocía ninguna, grachie :-)

Enviado por Jordi (no verificado) el Mar, 09/11/2004 - 18:07.
Imagen de Claudex

En serio que no? Creo que tendré que armar un pequeño post hablando del tema. Es bastante interesante!

Enviado por Claudex (no verificado) el Mar, 09/11/2004 - 23:06.
Imagen de Jordi

Seguro que no, en serio. Quizá sea porque nunca he usado Javascript con mucho interés... será porque lo odio :-)

Enviado por Jordi (no verificado) el Mié, 10/11/2004 - 07:12.

Enviar un comentario nuevo

El contenido de este campo se mantiene como privado y no se muestra públicamente.
If you have a Gravatar account, used to display your avatar.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Saltos automáticos de líneas y de párrafos.

Más información sobre opciones de formato