6 votes

Comment utiliser un appel asynchrone à l'intérieur d'un constructeur d'observable RxJs ?

Je suis en train de mettre en place un effect dans une application utilisant NgRx .

Pendant l'effet, j'ai besoin d'obtenir des valeurs de stockage, d'exécuter une certaine logique, puis de distribuer une ou plusieurs actions à la suite de la logique exécutée.

Donc, pour faciliter les choses, j'utilise un effet avec dispatch: false .

public getCachedOrServerValue$ = createEffect(() =>
    this.actions$.pipe(
      ofType(myActions.getCachedOrServerValue),
      switchMap((_) => this.getCachedOrServerValue())
    ), { dispatch: false }
);

Donc, dans l'exemple ci-dessus, je vais appeler getCachedOrServerValue . Je veux utiliser switchMap (plutôt que simplement tap ) donc si je reçois un nouveau myActions.getCachedOrServerValue avant que le précédent ne soit terminé, il annulera l'abonnement précédent (d'après ce que je comprends de switchMap).

La fonction que nous appelons ressemble à ce qui suit...

private getCachedOrServerValue(): Observable<void> {
  const result$ = new Observable<void>(async (subscriber) => { // <---- I need this to be async so I can use await
    // First see if we can get it from the store
    const cached = await this.storeUtils.getStoreValue(fromApp.getValue);
    if (cached) {
      this.store$.dispatch(myActions.getCachedOrServerValueSuccess(cached));
      subscriber.next();
      return;
    }

    // Need to request from the server
    const name = await this.storeUtils.getStoreValue(fromApp.getSiteName);

    // storeUtils.getStoreValue is just a helper we have to get a single value as a Promise
    const valueId = await this.storeUtils.getStoreValue(fromApp.getValueId);
    const serverValue = await this.myService.getValue(namevalueId);
    this.store$.dispatch(myActions.storeValue(serverValue));
    this.store$.dispatch(myActions.getCachedOrServerValueSuccess(cached));
  });
  return result$;
}

Tout d'abord, j'intègre un observable, car d'après ce dont je me souviens, nous avons besoin d'un observable pour utiliser cet appel au sein de switchMap

Deuxièmement (mon problème réel), je veux pouvoir utiliser await à l'intérieur de l'Observable subscriber argument de constructeur, mais VSCode rapporte une erreur...

enter image description here

Détails des erreurs...

L'argument de type '(this : Observable, subscriber : Subscriber) => Promise' n'est pas affectable au paramètre de type '(this : Observable, subscriber : Subscriber) => TeardownLogic'. Le type 'Promise' n'est pas assignable au type 'TeardownLogic'. La propriété 'unsubscribe' est manquante dans le type 'Promise' mais obligatoire dans le type 'Unsubscribable'.ts(2345)

types.d.ts(31, 5) : 'unsubscribe' est déclaré ici.

Quelqu'un a-t-il une idée de ce qu'est le problème ici, et comment je peux utiliser la aysnc/await comme indiqué ci-dessus ?

Merci d'avance

UPDATE

D'après la réponse de @StPaulis, je peux éviter d'avoir à le faire (du moins dans cette situation).

Je peux le faire comme suit (pas encore testé, mais je suis sûr que ça ira) ....

public getCachedOrServerValue$ = createEffect(() =>
  this.actions$.pipe(
    ofType(myActions.getCachedOrServerValue),
    switchMap(_ => from(this.getCachedOrServerValue()).pipe( // <-- use a from here 
         map(data => myActions.getCachedOrServerValueSuccess(data)),
         catchError(error => of(myActions.getCachedOrServerValueFail(error)))
))));

private async getCachedOrServerValue(): Promise<DataState>{
 // First see if we can get it from the store
 const cached = await this.storeUtils.getStoreValue(fromApp.getValue);
 if (cached) {
    return cached;
 }

 // Need to request from the server
 const name = await this.storeUtils.getStoreValue(fromApp.getName);
 const valueId = await this.storeUtils.getStoreValue(fromApp.getValueId);
 const serverValue = await this.myService.getValue(name, valueId);
 return serverValue;
}

1voto

StPaulis Points 2061

À mon avis, mélanger des observables avec des promesses n'est jamais une bonne idée.

Je vous suggère d'utiliser RxJs | de pour convertir votre promesse en observable et l'utiliser dans votre pipe au lieu de créer un nouvel observable et d'y intégrer toute la logique.

RxJs a pour but de remplacer la fonctionnalité (async | await).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X