0

I have a situation in which I need to wait for the observable to begin emitting values before the subsequent code executes. The closest I have gotten so far is like this:

async ensureContentLoaded() {
  if (!this.content) {
    defer(async () => {
      this.content = await this.getContent();
      console.log(`Got content`);
    }).subscribe();

    console.log(`Finished`);
  }

At the moment, the Finished console log is appearing before the Got content. I want the observable to 'block' until it starts to emit values. Note that this.getContent() returns a promise; although it could easily return an observable if that makes any difference. Also I know that this.content is referring to the wrong context, but that's another issue.

How can I create an observable that will block execution until a value is emitted?

serlingpa
  • 12,024
  • 24
  • 80
  • 130
  • what you ask is impossible in the general case - JavaScript engines are single-threaded, which means if you block the single thread to wait for an observable to produce a value, then there is no thread available for that async mechanism to run and produce its value – Brandon Feb 21 '19 at 16:38
  • 1
    describe _why_ you need this. The solution to your problem is _not_ to block while waiting on the observable. It is to make your other code asynchronous. – Brandon Feb 21 '19 at 16:39
  • Why not structure the code such that upon receiving the first value the code executes, rather than trying to block until then. To put it another way, execute a given callback when the first value emitted by a observable. – francium Feb 21 '19 at 16:41
  • I don't understand. If `getContent()` returns an `Observable`, why not `getContent().subscribe(() => console.log('Got content'))` ? – Arnaud Denoyelle Feb 21 '19 at 16:41
  • Thank you all for your responses. You're absolutely right Brandon and francium. I need to make the consuming code run asynchronously. I'll do it like that. – serlingpa Feb 21 '19 at 16:49
  • I am not sure if this scenario and refactoring I did will be of some help to you - but this may give you some ideas https://stackoverflow.com/questions/48150472/is-angulars-foreach-loop-over-an-object-asynchronous/54808339#54808339 – JGFMK Feb 21 '19 at 17:00

1 Answers1

0

THe following code should be sufficient.

ensureContentLoaded() {
  if (this.content) return of(this.content);
  return from(this.getContent());
}
// usage 
this.ensureContentLoaded().subscribe(console.log);
// or turn it to promise if needed
this.ensureContentLoaded().pipe(toPromise()).then(...)
Fan Cheung
  • 10,745
  • 3
  • 17
  • 39