Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to await inside RxJS subscribe method

Inside of an RxJS subject's subscribe callback, I want to await on an async function. Below is a code example which the typescript transpiler complains about saying:

Error:(131, 21) TS2304:Cannot find name 'await'.

async ngOnInit() {
  this.subscriber = dateSubscription.subscribe((date: Date) => {
    let dbKey = await this._someService.saveToDatabase(someObject);
    // wait for db write to finish before evaluating the next code
    // ... some other code here
  });
}

Usually I see this when trying to call await inside a non async function. Do I somehow need to make the subscribe callback async or am I going about this wrong? The function saveToDatabase is async and returns a promise resolving to the database primary key that was written to.

like image 437
apricity Avatar asked May 09 '17 23:05

apricity


People also ask

How do you await subscribe method?

you can achieve this using toPromise method. It is also a great way to handle asynchronous operations. Just remove the subscribe and add this method and add the async keyword in the method from where you are calling this method. const response = await this.

Is Observable subscribe async?

A common misconception in Angular development is regarding whether observables are synchronous or asynchronous. A lot of (even experienced Angular developers) think that observables are async, but the truth is that they can be… Both synchronous and asynchronous.

Can I use await on Observable?

You have to pass a promise to await . Convert the observable's next event to a promise and await that.

Is RxJS asynchronous?

RxJS is a library for composing asynchronous and event-based programs by using observable sequences. It provides one core type, the Observable, satellite types (Observer, Schedulers, Subjects) and operators inspired by Array#extras (map, filter, reduce, every, etc) to allow handling asynchronous events as collections.


3 Answers

you can just directly add async signature to the anonymous function call in subscribe

 this.subscriber = dateSubscription.subscribe(async (date: Date) => {
    let dbKey = await this._someService.saveToDatabase(someObject);
    // wait for db write to finish before evaluating the next code
    // ... some other code here
  });
like image 192
pearldiver Avatar answered Oct 02 '22 00:10

pearldiver


You do not need to use await, nor need to convert your Promise to an Observable.


CF this Tweet from Ben Lesh :

enter image description here


Here's an example with a mock for the function saveToDatabase :
(and the working Plunkr : https://plnkr.co/edit/7SDLvRS2aTw9gYWdIznS?p=preview)

const { Observable } = Rx;

const saveToDatabase = (date) =>
  new Promise(resolve =>
    setTimeout(() =>
      resolve(`${date} has been saved to the database`),
      1000));

const date$ = Observable.of(new Date()).delay(1000);

date$
  .do(x => console.log(`date received, trying to save it to database ...`))
  .switchMap(date => saveToDatabase(date))
  .do(console.log)
  .subscribe();

Output :
enter image description here

like image 27
maxime1992 Avatar answered Oct 02 '22 00:10

maxime1992


Update: Found easy for one time promises just use toPromise in front of the subscriber (blog). So for the above case it will be like this:

const title = await this.translate.get('MYBOOK-PAGE.PAGE_TITLE').toPromise();

Old way: Here's my method of solving this issue

const title = await new Promise<string>(resolve => 
  this.translate.get('MYBOOK-PAGE.PAGE_TITLE')
   .subscribe(translated => {
     resolve(translated)
   }));

Here what I'm doing is changing my Observable to a Promise

Note: Here the only problem is this is one time show ie. if you subscribe once you won't able to access it again. Suited me so sharing here.

like image 14
Black Mamba Avatar answered Oct 02 '22 01:10

Black Mamba