2016-04-20 3 views
11

Ich habe ein Szenario, in dem ich ein Versprechen zurückgebe. Das Versprechen geben grundsätzlich die Antwort einer Ajax-Anfrage.Was passiert, wenn wir das Versprechen nicht lösen oder ablehnen

Beim Zurückweisen des Versprechens zeigt es einen Fehlerdialog an, dass ein Serverfehler vorliegt.

Was ich tun möchte ist, wenn der Antwortcode 401 ist, möchte ich weder das Versprechen lösen noch lehnen (weil es Fehlerdialog zeigt). Ich möchte einfach auf die Login-Seite umleiten.

Mein Code sieht so etwas wie dieses

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

     }) 
    }); 
} 

Wie Sie sehen können, wenn der Status 401, Ich bin Umleitung zur Login-Seite. Versprechen wird weder gelöst noch abgelehnt.

Ist dieser Code in Ordnung? Oder gibt es einen besseren Weg, dies zu erreichen.

Danke.

Antwort

23

Ein Versprechen ist nur ein Objekt mit Eigenschaften in Javascript. Es gibt keine Magie. Wenn man also ein Versprechen nicht auflöst oder ablehnt, kann man den Zustand niemals von "ausstehend" zu etwas anderem ändern. Dies verursacht kein grundsätzliches Problem in Javascript, da ein Versprechen nur ein normales Javascript-Objekt ist. Das Versprechen wird weiterhin Müll gesammelt (auch wenn noch ausstehen), wenn kein Code einen Verweis auf das Versprechen enthält.

Die wirkliche Konsequenz hier ist, was bedeutet das für den Verbraucher des Versprechens, wenn sein Zustand nie geändert wird? Beliebige .then() Listener zum Auflösen oder Zurückweisen von Übergängen werden niemals aufgerufen. Der meiste Code, der Versprechungen verwendet, erwartet, dass sie irgendwann in der Zukunft auflösen oder ablehnen (deshalb werden Versprechungen an erster Stelle verwendet). Wenn dies nicht der Fall ist, wird dieser Code normalerweise nie seine Arbeit beenden.

Es ist möglich, dass Sie einen anderen Code haben, der die Arbeit für diese Aufgabe beendet, und das Versprechen wird einfach aufgegeben, ohne jemals sein Ding zu tun. Es gibt kein internes Problem in Javascript, wenn Sie es so machen, aber es ist nicht so, wie Versprechungen entworfen wurden, um zu funktionieren und es ist im Allgemeinen nicht so, wie der Verbraucher von Versprechungen erwartet, dass sie funktionieren.

Wie Sie sehen können, wenn der Status 401 ist, werde ich auf die Anmeldeseite umleiten. Versprechen wird weder aufgelöst noch abgelehnt.

Ist dieser Code in Ordnung? Oder gibt es einen besseren Weg, dies zu erreichen?

In diesem speziellen Fall ist alles in Ordnung und eine Weiterleitung ist ein etwas spezieller und einzigartiger Fall.Eine Umleitung auf eine neue Browserseite wird den aktuellen Seitenstatus (einschließlich des gesamten Javascript-Status) vollständig löschen, so dass es völlig in Ordnung ist, eine Verknüpfung mit der Umleitung zu nehmen und andere Dinge einfach ungelöst zu lassen. Das System wird Ihren Javascript-Status vollständig neu initialisieren, wenn die neue Seite geladen wird, damit alle Versprechen, die noch ausstehen, bereinigt werden.

+1

Wie Sie bereits erwähnt haben, wird durch eine Umleitung auf eine neue Browserseite der aktuelle Seitenstatus (einschließlich des gesamten Javascript-Status) vollständig gelöscht. Aber was passiert, wenn ich in eine einzelne Seiten-App umadressiere? Ich benutze ReactJS. Es wird also keine neue Browserseite geben, nur eine andere Ansicht. Ob es in Ordnung ist, in diesem Fall mit der Weiterleitung eine Abkürzung zu nehmen und andere Dinge ungelöst zu lassen. – Aniket

+0

@Aniket - Dann ist das ein anderer Fall, den Ihre Frage nicht beschreibt. Sie müssen sicherstellen, dass die Dinge ordnungsgemäß bereinigt werden, so dass Sie keine Speicherlecks haben. Ich habe keine Ahnung ob es ein Problem damit geben würde oder nicht. Das nächste Mal bitte diese Art von Informationen in Ihre Frage. – jfriend00

+0

Stellen Sie sicher, dass Sie keine Verweise auf die Funktionen "Ablehnen" und "Auflösen" haben, und hören Sie nicht nur auf, das Versprechen zu verweisen. Dann sollte GC einspringen. Anderenfalls, wenn Ihr Code immer noch auf "resolve" verweist, muss die Promise für den Fall, dass Ihr Code jemals "resolve()" aufruft, bei Ihnen bleiben. Hier ist ein Beispiel für eine Web-API, die Versprechen geben kann, wenn nicht vorsichtig: https://github.com/w3c/webcomponents/issues/674 – trusktr

5

Immer das Versprechen auflösen oder ablehnen. Selbst wenn Sie das Ergebnis gerade jetzt nicht verwenden, ist es eine sehr schlechte Übung, in dieses Problem einzudringen, denn es verspricht Liebe, um Fehler zu verschlingen, und je komplexer Ihr Code wird, desto schwieriger wird es, die wenigen zu finden Orte, an denen Sie ein Versprechen nicht ausdrücklich ausgefüllt haben (und Sie werden nicht einmal wissen, ob das das Problem ist).

2

Es funktioniert und ist nicht wirklich ein Problem, außer wenn ein Anrufer von makeRequest erwartet von Versprechen zu erfüllen. Also, Sie brechen den Vertrag dort.

Stattdessen können Sie das Versprechen verschieben oder (in diesem Fall) mit Statuscode/Fehler ablehnen.

2

Wie andere sagten, ist es wahr, dass es nicht wirklich ein Problem ist, wenn Sie ein Versprechen nicht auflösen/ablehnen. Auf jeden Fall würde ich das Problem etwas anders lösen:

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

Das bedeutet, würde ich jede schlechte Antwort Staat ablehnen und dann diese in Ihrem error handler Ihrer makeRequest behandeln.

3

Ich denke, dass das "was passiert, wenn wir nicht ablehnen" wurde gut beantwortet - es ist Ihre Wahl, ob Sie eine .then oder eine .catch hinzufügen.

Jedoch Ist dieser Code OK? Oder gibt es einen besseren Weg, dies zu erreichen. Ich würde sagen, es gibt zwei Dinge:

Sie sind ein Versprechen in new Promise Verpackung, wenn es nicht notwendig ist, und der fetch Anruf kann scheitern, sollten Sie darauf handeln, so dass Ihre Rufmethode nicht nicht sitzen und warten, ein Versprechen, das niemals gelöst werden wird.

Hier ist ein Beispiel (ich denke, das für Ihre Geschäftslogik funktionieren sollte, nicht 100% sicher):

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

dagegen Code Aufruf mit:

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

nichts log Will weil der Aufruf an http://example fehlschlägt, aber der catch-Handler nie ausgeführt wird.

+0

Ich wollte nur vermeiden, if (typeof json === "undefined") { // Redirect-Anfrage ist aufgetreten } Der Grund dafür ist, dass makeRequest von vielen anderen Funktionen aufgerufen wird, und ich muss das in jeder Funktion, die es aufruft, einchecken. – Aniket