web-dev-qa-db-fra.com

que se passe-t-il si nous ne résolvons pas ou ne rejetons pas la promesse

J'ai un scénario où je retourne une promesse. La promesse donne essentiellement la réponse d'une demande ajax.

En rejetant la promesse, une boîte de dialogue d'erreur indiquant une erreur de serveur s'affiche.

Ce que je veux faire, c'est quand le code de réponse est 401, je ne veux ni résoudre la promesse, ni la rejeter (car il affiche une boîte de dialogue d'erreur). Je veux simplement rediriger vers la page de connexion.

Mon code ressemble à quelque chose comme ça

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

        })
    });
}

Comme vous pouvez voir si le statut est 401, je redirige vers la page de connexion. La promesse n'est ni résolue ni rejetée.

Ce code est-il correct? Ou y a-t-il un meilleur moyen d'accomplir cela?.

Merci.

51
Aniket

Une promesse est juste un objet avec des propriétés en Javascript. Il n'y a pas de magie à cela. Donc, ne pas résoudre ou rejeter une promesse ne parvient pas à faire passer l'état "en attente" à autre chose. Cela ne pose aucun problème fondamental en Javascript car une promesse est juste un objet Javascript ordinaire. La promesse sera toujours récupérée (même si elle est toujours en attente) si aucun code ne conserve une référence à la promesse.

La conséquence réelle ici est ce que cela signifie pour le consommateur de la promesse si son état n’est jamais changé? Les .then() ou .catch() écouteurs pour les transitions de résolution ou de rejet ne seront jamais appelés. La plupart du code qui utilise des promesses s'attend à ce qu'ils soient résolus ou rejetés à l'avenir (c'est pourquoi les promesses sont utilisées en premier lieu). S'ils ne le font pas, alors ce code n'arrive généralement jamais à terminer son travail.

Il est possible que vous ayez un autre code qui termine le travail pour cette tâche et la promesse est simplement abandonnée sans jamais faire son travail. Si vous le faites de cette manière, il n’ya pas de problème interne en Javascript, mais ce n’est pas la façon dont les promesses ont été conçues pour fonctionner et en général, pas comment le consommateur de promesses les attend.

Comme vous pouvez voir si le statut est 401, je redirige vers la page de connexion. La promesse n'est ni résolue ni rejetée.

Ce code est-il correct? Ou y a-t-il un meilleur moyen d'accomplir cela?.

Dans ce cas particulier, tout va bien et une redirection est un cas un peu spécial et unique. Une redirection vers une nouvelle page de navigateur efface complètement l'état actuel de la page (y compris l'état de Javascript). Il est donc tout à fait possible de prendre un raccourci avec la redirection et de laisser les autres éléments non résolus. Le système réinitialisera complètement votre état Javascript lorsque la nouvelle page commencera à se charger afin que toutes les promesses encore en attente soient nettoyées.

73
jfriend00

Toujours résoudre ou rejeter la promesse. Même si vous n'utilisez pas le résultat pour le moment, malgré que cela fonctionne, c'est une très mauvaise pratique à prendre car les promesses amour d'avaler les erreurs, et plus votre code devient complexe, plus il sera difficile trouver les quelques endroits où vous n’avez pas rempli explicitement une promesse (et vous ne saurez même pas si c’est le problème).

7
kungphu

Je pense que l’on a bien répondu à la question "Que se passe-t-il si nous ne résolvons pas le rejet"? Vous avez le choix entre ajouter un .then ou un .catch.

Cependant, Ce code est-il correct? Ou y a-t-il un meilleur moyen d'accomplir cela . Je dirais qu'il y a deux choses:

Vous emballez une promesse dans new Promise quand cela n’est pas nécessaire et que l’appel fetchpeut échouer, vous devez agir pour que votre méthode d’appel ne reste pas en attente d’une promesse qui ne sera jamais résolue .

Voici un exemple (je pense que cela devrait fonctionner pour votre logique métier, pas à 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);
  })

En revanche, appelez votre code en utilisant:

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

N'enregistrera rien parce que l'appel à http://example échouera, mais le gestionnaire catch ne sera jamais exécuté.

4
CodingIntrigue

Cela fonctionne et ne pose pas vraiment de problème, sauf lorsqu'un appelant de makeRequest s'attend à être promis. Donc, vous rompez le contrat là-bas.

Au lieu de cela, vous pouvez différer la promesse ou (dans ce cas) rejeter avec code d'état/erreur.

2
nullpotent

Comme d'autres l'ont dit, il est vrai que le fait de ne pas résoudre/rejeter une promesse ne pose pas vraiment problème. Quoi qu'il en soit, je voudrais résoudre votre problème un peu différent:

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

Cela signifie que je rejetterais tout état de mauvaise réponse, puis le gérerais dans votre error handler de votre makeRequest.

2
Fidel90