2016-04-20 24 views
11

Ho uno scenario in cui sto restituendo una promessa. La promessa fornisce fondamentalmente la risposta di una richiesta Ajax.cosa succede se non risolviamo o rifiutiamo la promessa

In caso di rifiuto della promessa viene visualizzata una finestra di errore che indica un errore del server.

Quello che voglio fare è quando il codice di risposta è 401, non voglio né risolvere la promessa né rifiutarla (perché mostra la finestra di errore). Voglio semplicemente reindirizzare alla pagina di accesso.

Il mio codice simile a questa

function makeRequest(ur,params) { 

    return new Promise(function(resolve,reject) { 

     fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      if (status >= 200 && status < 300) { 
       response.json().then((data) => { 
        resolve(data); 
       }) 
      } 
      else { 
       if(status === 401) { 
        redirectToLoginPage(); 
       } 
       else { 
        response.json().then((error) => { 

         if (!error.message) { 
          error.message = constants.SERVER_ERROR; 
         } 
         reject({status,error}); 
        })  
       } 
      } 

     }) 
    }); 
} 

Come si può vedere se lo stato è 401, sto reindirizzamento alla pagina di login. La promessa non è né risolta né respinta.

Questo codice è OK? Oppure c'è un modo migliore per farlo.

Grazie.

risposta

23

Una promessa è solo un oggetto con proprietà in Javascript. Non c'è magia in esso. Quindi non riuscire a risolvere o rifiutare una promessa non cambia mai lo stato da "in sospeso" a qualsiasi altra cosa. Questo non causa alcun problema fondamentale in Javascript perché una promessa è solo un normale oggetto Javascript. La promessa otterrà comunque la raccolta dei rifiuti (anche se ancora in sospeso) se nessun codice mantiene un riferimento alla promessa.

La vera conseguenza è che cosa significa questo per il consumatore della promessa se il suo stato non viene mai modificato? Qualsiasi ascoltatore .then() per le transizioni di risoluzione o rifiuto non verrà mai chiamato. La maggior parte del codice che usa le promesse si aspetta che possano risolversi o rifiutare in futuro (ecco perché le promesse vengono utilizzate in primo luogo). Se non lo fanno, allora quel codice generalmente non arriva mai a finire il suo lavoro.

È possibile che si possa avere un altro codice che completa il lavoro per quel compito e la promessa è stata abbandonata senza mai fare il suo dovere. Non c'è alcun problema interno in Javascript se lo fai in questo modo, ma non è come le promesse sono state progettate per funzionare e generalmente non è come il consumatore di promesse si aspetta che funzioni.

Come si può vedere se lo stato è 401, sto reindirizzando alla pagina di accesso. La promessa non è né risolta né respinta.

Questo codice è OK? O c'è un modo migliore per farlo.

In questo caso particolare, è tutto OK e un reindirizzamento è un caso un po 'speciale e unico.Un reindirizzamento a una nuova pagina del browser cancellerà completamente lo stato corrente della pagina (incluso tutto lo stato di Javascript), quindi è perfettamente corretto prendere una scorciatoia con il reindirizzamento e lasciare semplicemente le altre cose irrisolte. Il sistema reinizializzerà completamente lo stato di Javascript quando la nuova pagina inizierà a caricarsi, così tutte le promesse che erano ancora in sospeso verranno ripulite.

+1

Come hai detto, Un reindirizzamento a una nuova pagina del browser cancella completamente lo stato corrente della pagina (incluso tutto lo stato di Javascript). Ma cosa succederà se mi sto reindirizzando in una singola app. Sto usando ReactJS. Quindi non ci sarà una nuova pagina del browser, solo una vista diversa. Se è perfettamente corretto prendere una scorciatoia in quel caso con il reindirizzamento e lasciare semplicemente le altre cose irrisolte. – Aniket

+0

@Aniket - Quindi questo è un caso diverso che la tua domanda non descrive. Dovrai assicurarti che le cose vengano pulite correttamente in modo da non avere perdite di memoria. Non ho idea se ci sarebbe un problema con questo in reazione o meno. La prossima volta metti questo tipo di informazioni nella tua domanda. – jfriend00

+0

Assicurati di non avere riferimenti alle funzioni 'reject' e' resolve', e non limitarti a fare riferimento alla promessa. Quindi, GC dovrebbe intervenire. Altrimenti, se il tuo codice fa ancora riferimento a 'resolve', ad esempio, la Promessa dovrà rimanere in sospeso nel caso in cui il tuo codice chiamasse sempre' resolve() '. Ecco un esempio di un'API Web che può perdere Promesse se non è attenta: https://github.com/w3c/webcomponents/issues/674 – trusktr

5

Sempre risolvere o rifiutare la promessa. Anche se non stai utilizzando il risultato in questo momento, nonostante questo lavoro, è una pessima pratica entrare perché le promesse amano per ingoiare errori, e più il codice diventa complesso, più difficile sarà trovare i pochi luoghi in cui non hai esplicitamente completato una promessa (in più non saprai nemmeno se questo è il problema).

2

Funziona e non è davvero un problema, tranne quando un chiamante di makeRequest si aspetta di soddisfare. Quindi, stai rompendo il contratto lì.

Invece, è possibile rinviare la promessa o (in questo caso) rifiutare con codice di stato/errore.

2

Come altri hanno affermato, è vero che non è davvero un problema se non si risolve/rifiuta una promessa. Comunque vorrei risolvere il problema un po 'diverso:

function makeRequest(ur,params) { 

    return new Promise(function(resolve,reject) { 

     fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      if (status >= 200 && status < 300) { 
       response.json().then((data) => { 
        resolve(data); 
       }) 
      } 
      else { 
       reject(response); 
      } 
     }) 
    }); 
} 

makeRequest().then(function success(data) { 
    //... 
}, function error(response) { 
    if (response.status === 401) { 
     redirectToLoginPage(); 
    } 
    else { 
     response.json().then((error) => { 
      if (!error.message) { 
       error.message = constants.SERVER_ERROR; 
      } 

      //do sth. with error 
     }); 
    } 
}); 

Ciò significa che avrei respingere ogni stato risposta male e quindi gestire questo nella vostra error handler del vostro makeRequest.

3

Penso che il "cosa succede se non risolviamo il rifiuto" è stato risolto bene - è la tua scelta se aggiungere uno .then o uno .catch.

Tuttavia, Questo codice è OK? O c'è un modo migliore per realizzare questo. Direi che ci sono due cose:

Stai avvolgendo una promessa in new Promise quando non è necessario e la fetch chiamata può fallire, si dovrebbe agire in quel modo che il metodo di chiamata non si siede e attendere una promessa che non sarà mai risolta.

Ecco un esempio (credo che questo dovrebbe funzionare per la logica di business, non sicuro al 100%):

const constants = { 
    SERVER_ERROR: "500 Server Error" 
}; 
function makeRequest(url,params) { 
    // fetch already returns a Promise itself 
    return fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      // If status is forbidden, redirect to Login & return nothing, 
      // indicating the end of the Promise chain 
      if(status === 401) { 
       redirectToLoginPage(); 
       return; 
      } 
      // If status is success, return a JSON Promise 
      if(status >= 200 && status < 300) { 
       return response.json(); 
      } 
      // If status is a failure, get the JSON Promise, 
      // map the message & status, then Reject the promise 
      return response.json() 
       .then(json => { 
       if (!json.message) { 
        json.message = constants.SERVER_ERROR; 
       } 
       return Promise.reject({status, error: json.message}); 
       }) 
     }); 
} 
// This can now be used as: 
makeRequest("http://example", {}) 
    .then(json => { 
    if(typeof json === "undefined") { 
     // Redirect request occurred 
    } 
    console.log("Success:", json); 
    }) 
    .catch(error => { 
    console.log("Error:", error.status, error.message); 
    }) 

Al contrario, chiamando il codice utilizzando:

makeRequest("http://example", {}) 
    .then(info => console.log("info", info)) 
    .catch(err => console.log("error", err)); 

non registrerà nulla perché la chiamata a http://example avrà esito negativo, ma il gestore catch non verrà mai eseguito.

+0

Volevo solo evitare if (typeof json === "undefined") { // La richiesta di reindirizzamento si è verificata } Il motivo per cui makeRequest è chiamato da molte altre funzioni e devo effettuare tale controllo in ogni funzione che lo chiama. – Aniket

Problemi correlati