2012-07-11 18 views
9

He escrito un script de nodo que obtiene algunos datos al solicitar datos de REST API (utilizando la solicitud de la biblioteca). Consiste en un par de funciones, así:cómo resolver 'estos' problemas con bibliotecas de nodos como asincronía y solicitud

var data = { /* object to store all data */ }, 
function getKloutData() { 
    request(url, function() { /* store data */} 
} 
// and a function for twitter data 

Porque quiero hacer algunas cosas después de ir a buscar toda la he utilizado la asíncrono biblioteca para ejecutar todas las funciones se ha podido recuperar de este modo:

async.parallel([ getTwitterData, getKloutData ], function() { 
    console.log('done'); 
}); 

Este todo funciona bien, sin embargo quería poner todo dentro de un modelo objeto por lo que se ha podido obtener varias cuentas a la vez:

function Fetcher(name) { 
    this.userID = '' 
    this.user = { /* data */ } 
    this.init(); 
} 
Fetcher.prototype.init = function() { 
    async.parallel([ this.getTwitterData, this.getKloutData ], function() { 
     console.log('done'); 
    }); 
} 
Fetcher.prototype.getKloutData = function(callback) { 
    request(url, function() { /* store data */ }); 
}; 

esto no funciona porque asíncrono y solicitar cambiar el presente contexto. La única manera de que pudiera llegar a su alrededor es mediante la unión de todo lo que pase por petición asincrónico y:

Fetcher.prototype.init = function() { 
    async.parallel([ this.getTwitterData.bind(this), this.getKloutData.bind(this) ], function() { 
     console.log('done'); 
    }); 
} 
Fetcher.prototype.getKloutData = function(callback) { 
    function saveData() { 
     /* store data */ 
    } 


    request(url, saveData.bind(this); 
}; 

¿Estoy haciendo algo mal o algo básico? Creo que volver al script y bifurcarlo en child_processes crea demasiados gastos generales.

Respuesta

9

Lo estás haciendo exactamente bien.

La alternativa es mantener una referencia al objeto siempre en el contexto en lugar de utilizar bind, pero que requiere un poco de gimnasia:

Fetcher.prototype.init = function() { 
    var self = this; 
    async.parallel([ 
     function(){ return self.getTwitterData() }, 
     function(){ return self.getKloutData() } 
    ], function() { 
     console.log('done'); 
    }); 
} 

Fetcher.prototype.getKloutData = function(callback) { 
    var self = this; 

    function saveData() { 
     // store data 
     self.blah(); 
    } 

    request(url, saveData); 
}; 

También se puede hacer la unión de antemano:

Fetcher.prototype.bindAll = function(){ 
    this.getKloutData = this.prototype.getKloutData.bind(this); 
    this.getTwitterData = this.prototype.getTwitterData.bind(this); 
}; 

Fetcher.prototype.init = function(){ 
    this.bindAll(); 
    async.parallel([ this.getTwitterData, this.getKloutData ], function() { 
     console.log('done'); 
    }); 
}; 
+3

La biblioteca Subrayado tiene una función muy útil llamada 'bindAll' que hace que esto sea menos dolorosa. Y si optas por CoffeeScript, puedes simplemente definir los métodos con la flecha adiposa y no tendrás que hacer ningún enlace explícito en absoluto. –

3

Puede guardar esto en otra variable:

var me = this; 

Entonces me es su this.

0

Crear una instancia del objeto con esta función:

function newClass(klass) { 
    var obj = new klass; 

    $.map(obj, function(value, key) { 
     if (typeof value == "function") { 
      obj[key] = value.bind(obj); 
     } 
    }); 

    return obj; 
} 

Esto hará au vinculación tomática de todas las funciones, por lo que obtendrá un objeto en el estilo OOP habitual, cuando los métodos dentro de los objetos tienen contexto de su objeto.

Así que una instancia que no objetos a través del:

var obj = new Fetcher(); 

Pero:

var obj = newClass(Fetcher); 
+0

mi pregunta original estaba en un entorno nodejs donde jQuery no tiene sentido. Además, los métodos 'bindAll' en guiones bajos y lodash (libs que funcionan en todos los entornos JS) están diseñados para hacer esto por usted. – askmike

Cuestiones relacionadas