0

Have a subscription thats being called after everything else gets set but i wanna wait till the subscription finshes. T

Tried using async await but that didnt work with me. No sure if I was doing it incorrectly

public getGlobeConfig() {
    this.sourceKey = 'test';query = 'query'
    // wait till this call finishes than hit the 
     console.log('htting')
    this.service
    .searchQuery(query)
    .subscribe(response => {
        this.sources = response.hits.hits.map(hit => 
        hit._source);
        if (this.sources.length > 0) {
            this.availableMetadata = Object.keys(
                this.sources[0].metadata[this.sourceKey]
            );
        }
    });
    console.log('hitting')
    return this.sources
}

This.sources is reaching as undefined because this.sources is being set in the subscriptioon

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Karam
  • 336
  • 5
  • 18
  • 1
    Does subscribe return a callback or promise, if so you could try `.subscribe(...).then(console.log('hitting'); return this.sources)` – joshhemphill Apr 25 '19 at 16:55
  • Looks like you've fallen for one of the classic blunders of async programming :). Async callbacks get called _after_ the function returns, not at the same time. While javascript makes it looks like the order of execution is `start search query` -> `run callback` -> `return a value`, it's actually `start search query` -> `return a value`; (sometime later:) `run callback`. Clalbacks don't have to be called right away. They could even be called days later. And the rest of your code doesn't wait for the callback to finish (hence async). – Garrett Motzner Apr 25 '19 at 17:00
  • Could you please clarify what libraries you are using, and give some more context as to where `searchQuery` is coming from? – Garrett Motzner Apr 25 '19 at 17:35

2 Answers2

3

The short answer is you cannot cause the code after the subscribe to wait. Having said that, by taking a step back and looking at your code, you should not subscribe within the getGlobeConfig method. What you probably should do is use the map operator within the getGlobeConfig method and let the consumer of the getGlobeConfig method subscribe:

public getGlobeConfig() {
  // ...
  return this.service.searchQuery(query).pipe(
    map(response => {
      // Transform the response to what you want
      // the consumer of this method to receive
    })
  );
}

Consumer:

getGlobeConfig().subscribe(sources => /* ... */)

One very common pitfall I am seeing from new RxJs developers is that they try to subscribe to Observables in a service and then want to return the data to the components. In most cases you do not subscribe within the services. Let the services operate on the data within RxJs operators and have the services return the transformed Observables. The end consumer (usually components) will then subscribe to the Observables returned by the services.

Sam Herrmann
  • 6,293
  • 4
  • 31
  • 50
0

Your problem is that you cannot return a synchronous value that is generated in an asynchronous call. The best you can do is return a promise (or other async object). This is what async await is designed to accomplish: it adds keywords that make it easier to wait for promises to finish but in the end you are still working with promises, and async functions always return promises.

Here's some simple examples:

function doSomethingWithPromise() {
  return somethingThatReturnsAPromise()
    .then((result) => result.calculateSomethingFromResult()) // `then` returns a promise with a result of the callback
}

Transformed to an async call:

async function doSomethingWithAsync() {
  // because this is an async function, it returns a promise here, before it finishes waiting
  let result = await somethingThatReturnsAPromise()
  return result.calculateSomethingFromResult() // at this point, after waiting, the function fulfills the promise with this return value
}

Those two examples are equivalent.

(This is a general example, and if you are using a library that uses streams or events instead of promises, for example, things may be different)

Garrett Motzner
  • 3,021
  • 1
  • 13
  • 30