2013-12-13 18 views
16

Sto cercando di riempire alcuni dati locali risolvendo una serie di chiamate remote.
Quando ogni promessa viene risolta, carico i dati e procedo.

Procedimento $q.all([]) fa esattamente questo:

 $q.all([ 
      this.getUserInfo(11) 
       .then(function (r) { 
        results.push(r) 
       }), 

      this.getUserConns() 
       .then(function (r) { 
        results.push(r) 
       }), 

      this.getUserCtxs() 
       .then(function (r) { 
        results.push(r) 
       }) 
     ]) 
     .then(function() { 
      console.log(results) 
     }) 


problema è, questo codice non è resiliente.
Se una di queste chiamate fallisce, nessuno prende il pesce!

avvolgendo le chiamate in un try/catch, semplicemente provoca $q.all() di ignorare del tutto la voce, anche quando non mancando (notare il console.log nel func) ...

 $q.all([ 
      this.getUserInfo2(11) 
       .then(function (r) { 
        results.push(r) 
       }), 

      function() { 
       try { 
        this.getUserGroups() 
         .then(function (r) { 
          console.log(r) 
          results.push(r) 
         }) 
       } 
       catch (err) { 
        console.log(err) 
       } 
      }, 
     ]) 
     .then(function() { 
      console.log(results) 
     }) 

uscita:

[oggetto]


Qualche suggerimento su come potrei avvolgere questo per essere resiliente?


Grazie a @dtabuenc, ho fatto un ulteriore passo avanti. Implementando la richiamata di errore, posso evitare la rottura della catena e spingere i valori delle promesse risolte.

Tuttavia, una cattiva eccezione viene ancora visualizzata sulla console ... Come posso sbarazzarmene se non riesco a provare/catturare richieste asincrone?

codice chiamante

return $q.all([ 

      this.getUserInfo(user_id) 
       .then(function (r) { 
        results['personal_details'] = r 
       }), 

      this.getUserConns() 
       .then(
        function (r) { 
        results['connections'] = r 
        }, 
        function(err) { 
         console.log(err) 
        }) 

     ]) 
     .then(function() { 
      return (results) 
     }) 

codice Callee (iniettare con un'eccezione)

getUserConns: function() { 

     return __doCall(ws.getUserConnections, {}) 
      .then(function(r) { 

       // very generic exception injected 
       throw new Error 

       if (r && r.data['return_code'] === 0) { 
        return r.data['entries'] 
       } 
       else { 
        console.log('unable to retrieve the activity - err: '+r.data['return_code']) 
        return null 
       } 
      }) 
    }, 

risposta

23

Ciò funzionerà ma anche gli errori nell'array.

function push(r) { 
    results.push(r); 
} 

$q.all([ 
    this.getUserInfo(11).then(push).catch(push), 
    this.getUserConns().then(push).catch(push), 
    this.getUserCtxs().then(push).catch(push) 
]) 
.then(function() { 
    console.log(results); 
}) 

Si dovrebbe anche migliorare la comprensione delle promesse, si mai dovrebbe usare try-catch con promesse - quando si utilizzano le promesse, si utilizza il metodo .catch() (con tutto il resto essendo implicitamente un try). Questo funziona per errori normali e errori asincroni.


Se si desidera ignorare completamente gli errori:

function push(r) { 
    results.push(r); 
} 

function noop() {} 

$q.all([ 
    this.getUserInfo(11).then(push).catch(noop), 
    this.getUserConns().then(push).catch(noop), 
    this.getUserCtxs().then(push).catch(noop) 
]) 
.then(function() { 
    console.log(results); 
}) 
+0

In realtà, sono ancora un principiante su Angular, promesse e persino JS, e sono più che felice di imparare cose nuove ogni giorno! Il metodo .catch() ancora non "blocca" l'eccezione che ho generato nel mio ultimo esempio, ma penso che sia il più vicino possibile al mio risultato ideale. Grazie! – domokun

+1

@domokun promesse angolari riportano erroneamente anche eccezioni rilevate, violando lo spirito di Promises/A + se non violando le specifiche – Esailija

+0

Buono a sapersi ... Immagino ... Thx again! – domokun

0

Non sono sicuro di cosa si intende per resiliente. Cosa vuoi che succeda se una delle promesse fallisce?

Il tuo try-catch non funzionerà perché la promessa fallirà in modo asincrono.

È tuttavia possibile passare un gestore di errori come secondo parametro alla chiamata then() e fare ciò che si desidera.

+0

Ok bene, ho dimenticato il callback dell'errore. È resistente, nel senso che la catena non viene interrotta, ed è quello che volevo. Tuttavia, non riesco a nascondere l'eccezione se non lo prendo ... aggiornerò la mia domanda per spiegare – domokun

+0

Non penso che tu possa intercettare errori HTTP. Verranno sempre visualizzati sulla console. Questo indipendentemente dal fatto che tu stia usando angolare o meno. – dtabuenc

+0

Questo è vero, e non mi infastidisce. Ciò che realmente mi infastidisce è la visualizzazione di un'eccezione sulla console. Si prega di dare un'occhiata alla mia domanda aggiornata – domokun

0

Stesso problema qui. Per quelli di voi con cicli for: all'interno di una risposta, allora:

var tracks = []; 
var trackDfds = []; 
for(var i = 0; i < res.items.length; i++){ 
    var fn = function() { 
     var promise = API.tracks(userId, res.items[i].id); 
     return promise.then(function (res) { 
      if (res.items.length) { 
       tracks.push(res.items); 
      } 
     }).catch(angular.noop); 
    }; 
    trackDfds.push(fn()); 
} 
$q.all(trackDfds) 
    .then(function (res) { 
     console.log(tracks); 
    }); 
1

Penso che sia più facile da fare:

$q.all([ 
mypromise1.$promise.catch(angular.noop), 
mypromise2.$promise.catch(angular.noop), 
mypromise1.$promise.catch(angular.noop) 
]) 
.then(function success(data) { 
//..... 
}); 
0

@ risposta di Esailija sembra una soluzione ad un problema. Non è possibile risolvere il problema al di fuori del principale contributore al problema: $q.

Sembra un po 'più saggio rifiutare le richiamate per ogni then (secondo argomento) e inserire qui $q.reject(...).

Esempio:

$q.all([ 
    this.getUserInfo(11).then(
     function (response) { // UI data preparation for this part of the screen }, 
     function (response) { 
      $q.reject(response); 
     } 
    ), 
    // ... 
]) 
.then(
    function() { 
     // all good 
    }, 
    function() { 
     // at least one failed 
    } 
) 

Ciò è particolarmente indicato quando il modello UI dipende da tutte le chiamate ajax.

Personalmente penso che questo sia il modo sicuro per procedere comunque, perché la maggior parte delle volte si desidera inviare alcuni messaggi server a qualche componente toast sui richiami rifiutati o avvisare l'utente in qualche modo (fare la coda 7 chiamate ajax non significa che non puoi mostrare nulla perché 1 non è riuscito - significa che non sarai in grado di mostrare alcune regioni dello schermo - che ha bisogno di un feedback specifico per l'utente).

Problemi correlati