AngualrJS $q
Hannes Weninger
- javascript
2 dedlfix
Hallo,
ich programmier jetzt schon einige Zeit in AngualrJS - aber keine "schwierigen" Sachen sondern nur MVC. Ich hab deshalb keine Ahnung, was dieser Code unten macht:
var currentUser = false;
...
function getCurrentUser() {
var deferred = $q.defer();
if(currentUser){
deferred.resolve(currentUser);
} else {
getCurrentUserFromAPI().success(function(data) {
if(data) {
currentUser = data;
return deferred.resolve(currentUser);
}
}).error(function(data) {
var token = authTokenService.getToken();
if(token) {
authTokenService.deleteToken();
}
return deferred.reject(data);
});
}
return deferred.promise;
}
Vor allem mit den $q- Statements komm ich gar nicht zu recht. Ich hab mir auch die Doku durchgelesen:
$q aber nicht sehr viel verstanden. Ich wäre sehr dankbar, wenn vielleicht jemand in kurzen worten beschreiben könnte, was obere Funktion macht.
Vielen Dank! Hannes
Tach!
Ich hab deshalb keine Ahnung, was dieser Code unten macht:
Das ist ein Promise - das Versprechen, dass es ein Ergebnis geben wird, aber nicht jetzt, sondern später. Deshalb gibt die Funktion erstmal nur das Promise zurück. Irgendwann später wird es erfüllt oder zurückgewiesen. Vom Promise wird dazu entweder resolve() oder reject() aufgerufen, was letztlich dazu führt, dass bei dir die entsprechenden Callback-Funktionen aufgerufen werden, damit du dann mit dem Ergebnis oder der Fehlermeldung was anfangen kannst.
Die Funktion definiert nicht nur ein Promise für dich, sie nutzt ihrerseits mit dem Aufruf von getCurrentUserFromAPI() ein weiteres Promise, um dann mit dessen Ergebnis (success) oder Misserfolg (error) dein Promise zu erfüllen oder zurückzuweisen.
Man kommt nicht drumherum, bestimmte Sachen asynchron auszuführen. Zum Beispiel kommt ein Ajax-Aufruf erst irgendwann später wieder und man möchte nicht die ganze Zeit die UI blockieren. Deshalb verwendet man ein Promise als eine Art definierter Callbacks für den Gut- und Fehlerfall. Man muss sich dann aber auch im Klaren sein, dass man nun nicht mehr drumherum kommt und alles vom Ergebnis abhängige entweder in den Callbacks erledigt oder, wenn man selbst nur Mittelsmann ist, auch selbst ein Promise erstellen muss.
Wenn du mit Promises anfangen möchtest/musst, nimm erstmal einen Ajax-Aufruf, dann bist du nämlich nur Nutzer und musst kein Promise selbst erstellen. Das kommt erst hinzu, wenn du Mittelsmann-Funktionen schreiben willst, die das Ergebnis vor dem Zurückgeben bearbeiten - oder auch die Eingangswerte vor dem Aufrufen einer asynchronen Verarbeitung.
Das mit dem defer() ist die eine Schreibweise. Ich verwende immer die andere, weil ich da mit etwas weniger Code auskomme: Einmal return $q()
aufrufen und eine Funktion übergeben, die mit resolve und reject zwei Funktionsreferenzen entgegennimmt. Der Rest (das was in der dem $q übergebenen Funktion stattfindet) ist dann das was die Aufgabenstellung erfordert.
function versprich_mir_was(irgendwelche_parameter) {
return $q(function (resolve, reject) {
var bearbeitete_parameter = bereite_vor(irgendwelche_parameter);
ruf_eine_andere_funktion_auf_die_ein_promise_liefert(bearbeitete_parameter)
.then(function (ergebnis) {
var bearbeitetes_ergebnis = mach_was_mit_dem_ergebnis(ergebnis);
resolve(bearbeitetes_ergebnis);
})
.catch(function (fehler) {
console.log(fehler);
reject(fehler);
});
});
}
In der Regel hat man selbst solchen Code, der ein anderes Promise nutzt, weil man irgendwelche asynchronen Dinge nutzen muss. Es ist kaum so, dass man selbst etwas Asynchrones neu aufsetzt. In den Beispielen wird immer gern mit einem Timeout gearbeitet, um eine Verzögerung darzustellen. In der Praxis wird die Nutzung von Promises meist wegen einer Ajax-Verwendung stattfinden. Ich hab aber auch schon einen Dialog in ein Promise gepackt. Der Dialog wird initialisiert und der Aufrufer bekommt nur ein Promise. Wenn der Anwender später den Dialog mit OK schließt, wird das Promise mit resolve() erfüllt und bei Abbruch mit reject() zurückgewiesen. An der Stelle der Verwendung ist das eine ziemlich übersichtliche Geschichte. Herkömmlich würde man Eventhandler für die Buttons schreiben und hätte eine Menge Code an der Stelle.
zeige_dialog(parameter)
.then(function (ergebnis) {
// tu was damit
});
// kein catch notwendig, wenn man bei Abbruch nichts machen möchte
dedlfix.
Vielen Dank für die Erklärung!!! Jetzt ist es mir einigermaßen klar. Was mir bei meinem code noch nicht klar ist ist folgendes Statement:
deferred.resolve(currentUser);
currentUser ist ja true oder false und mir ist nicht klar. was resolve mit dem flag
vielen dank! Hannes
Tach!
Was mir bei meinem code noch nicht klar ist ist folgendes Statement:
deferred.resolve(currentUser);
currentUser ist ja true oder false und mir ist nicht klar. was resolve mit dem flag
currentUser ist kein Flag. Die Variable hat nur jemand mit false initialisiert, was augenscheinlich anzeigen soll, dass die Daten vom current User nicht vorhanden sind und sie erst noch abgefragt werden müssen. Besser wäre es, die Variable mit null zu initialisieren. Das ist auch ein falsy Wert, mit dem die if-Bedingung dieselbe Verzweigung nimmt. Aber es hätte vermutlich dich nicht fälschlicherweise zur Annahme kommen lasse, die Variable sei ein boolescher Wert.
Jedenfalls ist der Teil
if(currentUser){
deferred.resolve(currentUser);
}
eine Abkürzung, die das Promise sofort erfüllt, wenn der User bereits früher schon ermittelt wurde. In currentUser stehen bereits dessen Daten (ein Objekt vermutlich), und das ist für das if ein truthy Wert. Das Promise liefert dir in dem Fall den Inhalt von currentUser.
dedlfix.
Besten Dank! jetzt ist es klar! Danke! Hannes