如何避免RxJs订阅回调地狱?

Jam*_*mes 5 observable rxjs typescript angular

我正在使用Angular RxJs subscribe进行HttpClient通话,然后使用第一个通话中的值进行另一个通话。在这种情况下,有一个调用get address object,然后我使用该对象进行了调用。像这样:

@Injectable()
export class AddressService {
  constructor(private http: HttpClient) { }

  getById(addressId: string, userId: string) {
    return this.http.get(BACKEND_URL + 'getAddressById/' + [addressId, userId]);
  }
}
  
export class AddressModalComponent implements OnInit {
  constructor(private alertService: AlertService, private addressService: AddressService,           @Inject(MAT_DIALOG_DATA) public data: any, private dropdownService: DropdownService)

  ngOnInit() {
    this.addressService.getById(this.data.id, this.data.userId)
        .subscribe(
          (address: Address) => {
            this.dropdownService.getCidadesBrByEstado(address.name)
              .subscribe((cities: BrCity[]) => {
                this.cities = cities;
                this.address = address;
              },
              error => console.log(error));
          }, error => { this.alertService.error(error);
          }
        );
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我试图避免多个订阅,我的代码中有很多这样的订阅。我需要Async/Await类似的方法Node.js promises,但在组件级别使用Observables。我不太熟悉RxJs commands...是否有更好的方法仅用一个subscribe和一个就可以打很多电话catch

lei*_* li 6

对于使用 RxJS 时的 Angular,建议使用 Observable 类。为了解决 RxJS 中的回调地狱,您可以使用 Observable 的 Operators api,例如 switchMap() 方法(针对不同场景的更多方法是 map()、concatMap()...)。下面是我使用 switchMap() 方法的例子:
(1)我遇到的情况:我想订阅 serviceC,但是 serviceC 需要订阅 serviceB,serviceB 需要订阅 serviceA

const serviceA(params): Observable<any>;
const serviceB(params): Observable<any>;
const serviceC(params): Observable<any>;

serviceA(paramsA).subscribe(
    serviceAResult => {
        serviceB(paramsB).subscribe(
            serviceBResult => {
                serviceC(params).subscribe(
                    serviceCResult => {
                        // here is my logic code. Oh, Shit subscribe hell!
                    }
                )
            }
        )
    }
)
Run Code Online (Sandbox Code Playgroud)

(2)使用switchMap()方法优化代码结构

const serviceB$ = serviceA(paramsA).pipe(
    switchMap(serviceAResult => {
        return serviceB(paramsB);
    })
);

const serviceC$ = serviceB$.pipe(
    switchMap(serviceBResult => {
        return serviceC(paramsC);
    })
);

serviceC$.subscribe(
    serviceCResult => {
        // here is my logic code.
    },
    error =>{
        // handle error
    }
);
Run Code Online (Sandbox Code Playgroud)

关于处理回调地狱的好文章。

  • 虽然链接可能很方便,但最好在此处包含解决方案的本质,以防链接脱机或移动。 (4认同)

kct*_*ang 5

尝试类似:

import { map, switchMap } from 'rxjs/operators'

this.addressService.getById(this.data.id, this.data.userId).pipe(
  switchMap(address => this.dropdownService.getCidadesBrByEstado(address.name).pipe(
    // this pass both cities and address to the next observable in this chain
    map(cities => ({ cities, address }))
  ))
).subscribe(({ cities, address }) => {
  this.cities = cities
  this.address = address
})
Run Code Online (Sandbox Code Playgroud)

  • 这个答案看起来就像回调地狱。它只是比问题中的代码更简洁。想象一下通过 4-5 个连续的 http 请求来执行此操作。它会通过 switchMaps 和管道向右扩展和向下扩展一样多,并产生典型的回调地狱视觉效果。 (3认同)