Neulich bei der Code-Review in einem Angular-Team (ein fiktiver Dialog):
getAllMovies(): Promise<Movie[]> { return this.http.get<Movie[]>('/movies').toPromise(); }
Peter: Sieht alles tiptop aus – du wirst immer besser! Nur hier bei getAllMovies() würde ich direkt das Observable zurückgeben. Promises sind oldschool, die verwendet man nicht mehr.
Michi: Auch wenn man die Promises mit async/await aufruft statt mit .then()?
Peter: Ein Promise bleibt ein Promise. Promises sind hässlich. RxJS-Observables dagegen sind unglaublich vielseitig. Da kannst du asynchrone Operationen cachen, abbrechen, wiederverwenden, alles mit Bordmitteln. Die passen auch perfekt in ereignisgetriebene Architekturen.
Michi: Aha?
Peter: In der kommenden Version von RxJS haben sie die Methode toPromise() eh komplett entfernt.
Michi: Ist das nicht nur, weil sie sie durch firstValueFrom() und lastValueFrom() ersetzt haben? Diese Methoden geben ja ebenfalls Promises zurück.
Peter: Sie hatten wohl noch nicht den Mut für den grossen Schnitt.
Michi: Nur zur Erklärung: Ich dachte, ich gebe hier ein Promise zurück, damit du als Aufrufer beruhigt darauf vertrauen kannst, dass im subscribe() nur ein einziges Mal ein Array zurückkommt. Bei einem Observable weisst du ja nie, was du kriegst – es könnte unzählige Male eine Antwort mit immer wieder einem neuen Array daherkommen. Deshalb musst du bei jedem Aufruf extra noch pipe(first()) dranhängen, damit das Observable nach getaner Arbeit sicher wieder aus dem Speicher geräumt wird. Oder schlimmer: Du rufst nach dem subscribe() ein explizites unsubscribe() auf.
Peter: Blödsinn! Niemand macht das, sicher nicht, wenn eine REST-Abfrage dahintersteht. Der http-Client von Angular stellt von sich aus sicher, dass das Observable beendet wird, sobald die Antwort da ist. Problem gelöst.
Michi: Und wie kannst du als ahnungsloser Aufrufer dir so sicher sein, dass ich in getAllMovies() nur einmalig die Filmliste via http-Client abfrage? Ich könnte genauso gut via pipe() alle 10 Sekunden eine Aktualisierung nachschicken, ohne dass du es merkst. Dann lebt dein Observable bis zum jüngsten Tag weiter.
Peter: Ich sehe den Code deiner Methode – da gibt es kein pipe().
Michi: Ich könnte das schon morgen ändern.
Peter: Würdest du aber nicht.
Michi: Mein Punkt ist –
Peter: Michi, Michi! Hast du heute mit der falschen Hand die Tastatur entsperrt? Bei einer Code-Review muss man auch mal zugeben können, dass man falsch liegt. Lösche einfach das Promise raus und gut ist, OK? Und ich hole endlich den Kaffee, den ich vorhin rausgelassen habe. Der ist jetzt hundertpro kalt.
Michi kratzt sich am Bart. Blickt nach links, nach rechts. Schielt zu Peter am Kaffeeautomaten. Dann ändert er den Code auf
getAllMovies(): Observable<Movie[]> { return this.http.get<Movie[]>('/movies').pipe(repeat({delay: 10000})); }
und checkt ihn in den master-Branch ein.
Pingback: Noser Blog Wie oft npm-Packages updaten? - Noser Blog