2012-07-11 9 views
9

Ho scritto uno script di nodo che ottiene alcuni dati richiedendo i dati dell'API REST (usando la richiesta di libreria). Si compone di un paio di funzioni in questo modo:come risolvere "questo" problemi con le librerie di nodi come asincrona e richiesta

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

Perché voglio fare alcune cose, dopo il recupero tutto l'ho usato l'asincrona libreria per eseguire tutte le funzioni di recupero in questo modo:

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

Questo tutto funziona benissimo, però ho voluto mettere tutto all'interno di un modello di oggetto così ho potuto prendere più account contemporaneamente:

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 */ }); 
}; 

questo non funziona perché asincrona e richiesta di modifica del presente contesto. L'unico modo ho potuto ottenere intorno è legando tutto ciò mi passano attraverso richiesta asincrona e:

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); 
}; 

sto facendo qualcosa di sbagliato di base o qualcosa del genere? Penso che tornare alla sceneggiatura e lanciarlo a child_processes crei troppo sovraccarico.

risposta

9

Lo stai facendo esattamente nel modo giusto.

L'alternativa è quella di mantenere un riferimento all'oggetto sempre in un contesto invece di utilizzare bind, ma che richiede una certa ginnastica:

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); 
}; 

È anche possibile fare il legame a priori:

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 Underscore ha una comoda funzione chiamata 'bindAll' che rende questo meno doloroso. E se opti per CoffeeScript, puoi semplicemente definire i metodi con la freccia grossa e non dovrai fare alcun legame esplicito. –

3

È possibile salvare questo in un'altra variabile:

var me = this; 

Poi me è il vostro this.

0

Istanziare l'oggetto con questa funzione:

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

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

    return obj; 
} 

Questo farà au associazione tomatic di tutte le funzioni, in modo da ottenere oggetto in stile OOP abituale, quando i metodi all'interno degli oggetti hanno il contesto dell'oggetto.

Quindi istanziare non oggetti attraverso il:

var obj = new Fetcher(); 

Ma:

var obj = newClass(Fetcher); 
+0

la mia domanda originale era in un ambiente nodejs in cui jQuery non ha senso. Anche i metodi 'bindAll' in underscore e lodash (librerie che funzionano in tutti gli ambienti JS) sono progettati per fare questo per te. – askmike

Problemi correlati