Is it a good practice using Observable with async/await?

后端 未结 2 661
时光说笑
时光说笑 2020-12-04 10:33

I am using angular 2 common http that return an Observable, but I face with a problem that my code likes a mesh when I use nested Observable call:

this.serv         


        
2条回答
  •  伪装坚强ぢ
    2020-12-04 11:39

    As @Pac0 already elaborated on the various solutions well, I will just add slightly different angle.

    Mixing Promises and Observables

    I personally prefer not mixing Promises and Observables - which is what you get while using async await with Observables, because even though they look similar, they are very different.

    • Promises are always async, Observables not necessarily
    • Promises represent just 1 value, Observables 0, 1 or many
    • Promises have very limited use, you can't eg. cancel them (put aside ES next proposals), Observables are so much more powerful in their use (you can manage for example multiple WS connections with them, try that with Promises)
    • Their APIs differ greatly

    Use of Promises in Angular

    Now even though it is sometimes valid to use both, especially with Angular I think one should consider going as far with RxJS as possible. The reasons being:

    • Great portion of Angular API uses Observables (router, http ...), so one kind of goes with and not against the stream (no pun intended) by using RxJS, otherwise one would have to convert to Promises all the time while making up for the lost possibilities RxJS provides
    • Angular has powerful async pipe which allows for composing your whole application data flow of streams which you filter, combine and do whatever modification you want on it without interrupting the stream of data coming from server without a single need for thening or subscribing. This way, you don't need to unwrap the data or assign it to some auxiliary variables, the data just flows from services through Observables straight to the template, which is just beautiful.

    There are some cases though where Promise still can shine. For example what I am missing in rxjs TypeScript types is concept of single. If you are creating an API to be used by others, returning Observable is not all that telling: Will you receive 1 value, many, or will it just complete? You have to write comment to explain it. On the other hand, Promise has much clearer contract in this case. It will always resolve with 1 value or reject with error (unless it hangs forever of course).

    Generally, you definitely don't need to have only Promises or only Observables in your project. If you just want to express with a value that something was completed (deleting user, updating user), and you want to react on it without integrating it to some stream, Promise is the more natural way of doing so. Also, using async/await gives you the power to write code in sequential manner and therefore simplifying it greatly, so unless you need advanced management of incoming values, you can stay with Promise.


    Back to your example

    So my recomendation is to embrace both the power of RxJS and Angular. Coming back to your example, you can write the code as following (credits for the idea to @Vayrex):

    this.result$ = Observable.forkJoin(
      this.serviceA.get(),
      this.serviceB.get(),
      this.serviceC.get()
    );
    
    this.result$.subscribe(([resA, resB, resC]) => ...)
    

    This piece of code will fire 3 requests and once all of those request Observables have completed, subscription callback to forkJoin will get you the results in an array, and as said, you can subscribe to it manually (as in the example) or do this declaratively using result$ and async pipe in the template.

    Using Observable.zip would get you the same result here, the difference between forkJoin and zip is that the former emits only last values of inner Observables, the latter combines first values of the inner Observables, then second values etc.


    Edit: Since you need the results of previous HTTP requests, use flatMap approach in @Pac0's answer.

提交回复
热议问题