最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Observable async vs sync - Stack Overflow

programmeradmin2浏览0评论

How do I know when an Observable producer is async or sync?

An sync example:

Observable.of([1, 2, 3])

another async example (ngrx Store, see here)

this.store.take(1);

And now an obvious async example:

this.http.get(restUrl)

I fully understand how this works, and that some Observables can be sync and others Async. What I don't understand is how i can tell the difference in advance? Is there for example an obvious interface on the producer that tells me that it will be async?

tl;dr

The main reason this question has come up is because of the answer from the link above (here). @Sasxa has (correctly) answered that we can use a synchronous call to get the latest value from the ngrx store:

function getState(store: Store<State>): State {
    let state: State;

    store.take(1).subscribe(s => state = s);

    return state;
}

However knowing that observables are usually asynchronous, I saw this and immediately thought RACE CONDITION! the method could return an undefined value before subscribe has called back the function.

I've debugged through the internals of Store and Observable and this example is indeed synchronous, but how should I have known that? For those that know ngrx, the select method of store (used to get the latest values) is asynchronous, without a doubt, as this is what gives us the reactive gui, which is why I came to the assumption I did.

It means that I cannot refactor the code above as follows:

function getLatest(observable: Observable): any {
    let obj: any;

    observable.take(1).subscribe(latest => obj = latest);

    return obj;
}

I could call this with any Observable and it would work for synchronous producers - it may even work SOME OF THE TIME for async producers, but this is without a doubt a race condition if an async observable is passed in.

How do I know when an Observable producer is async or sync?

An sync example:

Observable.of([1, 2, 3])

another async example (ngrx Store, see here)

this.store.take(1);

And now an obvious async example:

this.http.get(restUrl)

I fully understand how this works, and that some Observables can be sync and others Async. What I don't understand is how i can tell the difference in advance? Is there for example an obvious interface on the producer that tells me that it will be async?

tl;dr

The main reason this question has come up is because of the answer from the link above (here). @Sasxa has (correctly) answered that we can use a synchronous call to get the latest value from the ngrx store:

function getState(store: Store<State>): State {
    let state: State;

    store.take(1).subscribe(s => state = s);

    return state;
}

However knowing that observables are usually asynchronous, I saw this and immediately thought RACE CONDITION! the method could return an undefined value before subscribe has called back the function.

I've debugged through the internals of Store and Observable and this example is indeed synchronous, but how should I have known that? For those that know ngrx, the select method of store (used to get the latest values) is asynchronous, without a doubt, as this is what gives us the reactive gui, which is why I came to the assumption I did.

It means that I cannot refactor the code above as follows:

function getLatest(observable: Observable): any {
    let obj: any;

    observable.take(1).subscribe(latest => obj = latest);

    return obj;
}

I could call this with any Observable and it would work for synchronous producers - it may even work SOME OF THE TIME for async producers, but this is without a doubt a race condition if an async observable is passed in.

Share Improve this question asked Nov 6, 2017 at 11:10 Forge_7Forge_7 1,9432 gold badges20 silver badges20 bronze badges 4
  • I don't know more generally, but the store uses a BehaviouralSubject, which is always sync because it's pre-loaded with a value (initial state, in the ngrx example) and always provides you with the 'latest' value on subscription. – Joe Commented Nov 6, 2017 at 11:16
  • @Sami - apparently not for ngrx/store v2.x. If you read Sasxa answer in the link, you'll see the code that made me create this question in the first place. – Forge_7 Commented Nov 6, 2017 at 15:43
  • Joe - ah that's interesting. I noticed BehaviouralSubject when debugging through the code. Does seem that ngrx is quite a specific example of sync behaviour. Thanks! – Forge_7 Commented Nov 6, 2017 at 15:45
  • @Forge_7 Yes, I see, sloppy of me. I will delete the comment, since it's not helpful. – Sami Hult Commented Nov 6, 2017 at 15:48
Add a comment  | 

2 Answers 2

Reset to default 8

It is hard to figure out whether an observable you get is sync or async (imagine you get observables return from a thrid party library). That's why you write it in a fashion that the execution order is controlled and predictable.

That's also why there are operators like concat, combineLatest, forkjoin, switchMap, race, merge to help you get the order and performance right for different scenario

It is possible to determine if an observable is asynchronous for sure if was directly scheduled with asynchronous scheduler (Scheduler.async or Scheduler.asap), it's exposed as foo$.scheduler:

let schedulers = [null, Scheduler.asap];
let randomScheduler = schedulers[~~(Math.random()*2)]
let foo$ = Observable.of('foo', randomScheduler);

This information becomes even less available when foo$ is processed further, e.g. chained with other operators.

And it's impossible to determine if values will be produced synchronously (on same tick) or asynchronously because this depends on observable internals:

let foo$ = new Observable(observer => {
  if (~~(Math.random()*2))
    setTimeout(() => observer.next('foo'));
  else
    observer.next('foo');
});

TL;DR: it's impossible to know this for sure.

发布评论

评论列表(0)

  1. 暂无评论