2015-12-20 9 views
6

Voglio creare un oggetto in Javascript.Accedere a "questo" di un oggetto all'interno della promessa di callback (quindi)

Uno dei metodi dovrebbe eseguire una catena di promesse. Ciascuno dei metodi nella catena deve accedere a una variabile di configurazione che è un membro dell'oggetto. Il problema è che l'operatore this viene modificato in PromiseMethod2 e non riesco ad accedere alla variabile di configurazione (Funziona correttamente in PromiseMethod1).

Ecco il mio codice:

var SomeObject(config) { 
    var that = this; 
    that.config = config; 
} 

SomeObject.prototype.SomeMethod = function() { 
    var that = this; 

    that.PromiseMethod1() 
     .then(that.PromiseMethod2) 
     .catch(console.error); 
    } 

SomeObject.prototype.PromiseMethod1 = function() { 
    var that = this; 
    config = that.config; 

    return SomePromise(); 
} 

SomeObject.prototype.PromiseMethod2 = function(someParams) { 
    var that = this; 
    config = that.config; 
    params = someParams; 

    return SomePromise(); 
} 


var someObject = new SomeObject(someConfig); 
someObject.SomeMethod().then(function() { 
    console.log('Done!'); 
} 

voglio usare il metodo delegato della catena invece di esecuzione:

that.PromiseMethod1().then(function(response) { return that.PromiseMethod2(that, response); }; 

non posso utilizzare il metodo bind perché sembra che si riapre quando viene eseguita la richiamata.

C'è una soluzione a questo? Perché c'è una differenza tra PromiseMethod1 e PromiseMethod2?

+0

Come si risolve 'SomePromise'? – Kiril

+0

Ogni metodo può fare cose diverse. Per lo più uso 'nuova promessa (risoluzione, rifiuto)' e quindi risolvo (somePrams). Oppure uso una promessa di terze parti come ElasticSearch o Promessa di richiesta – shudima

+0

Hai affermato che non puoi usare bind, ma ci hai provato? Sembra che sia la soluzione giusta. –

risposta

1

mio vera raccomandazione non è per utilizzare this o new affatto (ed è possibile utilizzare Object.create se si desidera ancora l'ereditarietà):

var SomeObject = function(config) { 
    return { 
     PromiseMethod1: function(){ 
      return somePromise(config.foo); 
     }, 
     PromiseMethod2: function(x){ 
      return someOtherPromise(config.bar, x); 
     } 
    } 
} 

var instance = SomeObject({config: true}); 
instance.PromiseMethod1().then(instance.PromiseMethod2); 

Qui sto usando le chiusure e la loro capacità di includere variabili del loro ambito lessicale genitore, a mio vantaggio. Piuttosto che fare affidamento su JavaScript per iniettare magicamente un this nella mia funzione in fase di esecuzione in base a quale oggetto è richiamata la funzione, perché, come dimostrato dal problema, non sempre funziona.

Tuttavia, so che il suo modo non convenzionale per lavorare, quindi se si preferisce attaccare con this, avrete bisogno di utilizzare bind per raccontare JavaScript che magica this -value la funzione appartiene:

var SomeObject function(config) { 
    this.config = config; 
} 

SomeObject.prototype.PromiseMethod1 = function(){ 
    return somePromise(this.config.foo); 
} 

SomeObject.prototype.PromiseMethod1 = function(x){ 
    return someOtherPromise(this.config.bar, x); 
} 

var instance = new SomeObject({config: true}); 
instance.PromiseMethod1().then(instance.PromiseMethod2.bind(instance)); //<- :(

Nell'esempio SomeMethod in realtà non si utilizza bind. Hai ancora bisogno di legare perché stai passando la funzione in .then(f), e il codice che riceve la funzione non sa più quale oggetto dovrebbe usare per lo this. Ora guarda di nuovo il mio codice consigliato in precedenza.Non ci sono this ses lì, quindi quelle funzioni non si basano affatto su quale oggetto vengono chiamate, puoi passarle come funzioni di ordine superiore quanto vuoi senza dover mai fare a bind o that = this . :)

0

Direi che è impossibile. Si tenta di combinare 2 approcci diversi: method chaining e promises chaining. Consiglierei di rivedere la tua architettura.

L'unica cosa visibile (ma personalmente non mi piace) se si ha il pieno controllo su tutte le promesse che si desidera utilizzare è di passare i valori di configurazione attraverso l'intera catena di promesse.

SomeObject.prototype.init = function() { 
    var that = this; 

    return new Promise(function(resolve, reject) { 
     resolve(that.config) 
    }); 
} 
SomeObject.prototype.PromiseMethod1 = function(config, params) { 
    return SomePromise(config, params); 
} 

SomeObject.prototype.PromiseMethod2 = function(config, someParams) { 
    return SomePromise(config, someParams); 
} 

SomePromise = function(config, params) { 
    return new Promise(function(resolve, reject) { 
     //some code here 
     resolve(config, newParamsFromSomeCode) 
    }); 
} 

Allora sarete in grado di chiamare:

that.init().then(that.PromiseMethod1).then(that.PromiseMethod2); 

Ma ancora una volta, non sembra come un buon codice ...

+0

Non esiste alcun metodo di concatenamento. tutti i metodi sono sotto SomeObject. Ho provato questo approccio, il problema è che il metodo di promessa non supporta più di 1 argomento. – shudima

+0

Sì, ma si desidera chiamare i metodi dello stesso oggetto uno per uno. Se hai davvero bisogno di codice asincrono, ti consiglio di mettere le tue operazioni asincrone in oggetti/livelli/componenti/oggetti separati e usare semplici concessioni di promesse. – Kiril

Problemi correlati