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

javascript - RxJS Observable returns data immediately, why? - Stack Overflow

programmeradmin4浏览0评论

In my current project I've found the function given below:

translateString(stringToTranslate: string) {
    let translation;
    this.translateService.get(stringToTranslate).subscribe(
        data => {
            translation = data;
        });
    return translation;
}

It looks ridiculous since TranslateService.get() method returns an Observable in every case, but it actually works somehow (the translated string is returned immediately)... What is the explanation of this behavior? Shouldn't callback function be added to the execution stack and run later?

In my current project I've found the function given below:

translateString(stringToTranslate: string) {
    let translation;
    this.translateService.get(stringToTranslate).subscribe(
        data => {
            translation = data;
        });
    return translation;
}

It looks ridiculous since TranslateService.get() method returns an Observable in every case, but it actually works somehow (the translated string is returned immediately)... What is the explanation of this behavior? Shouldn't callback function be added to the execution stack and run later?

Share Improve this question asked Mar 21, 2017 at 13:26 Daniel KucalDaniel Kucal 9,2427 gold badges46 silver badges69 bronze badges 3
  • it just looks like your value is returned to subscribe before translation variable is returned. It would be unreliable though, you are likely to get undefined translation.Observable will return value to subscriber when it gets it. – Suraj Rao Commented Mar 21, 2017 at 13:30
  • @suraj, the question is why? I think it's something about Observable.of(string) – Daniel Kucal Commented Mar 21, 2017 at 13:34
  • Looking at the code I suppose it could be going to the final else which is just an Observable of a value and will return without delay.But as I mentioned it is unreliable.. – Suraj Rao Commented Mar 21, 2017 at 13:56
Add a ment  | 

4 Answers 4

Reset to default 9

The fact you're using Observables doesn't automatically mean that everything is going to be called in a separate JavaScript callback.

In fact most of the default Observables and operators emit everything immediately and don't use any Scheduler by default. For example have a look at this https://github./ReactiveX/rxjs/blob/master/src/observable/ArrayObservable.ts#L118

This is obviously different when using for example the delay() operator which needs to schedule execution, see https://github./ReactiveX/rxjs/blob/master/src/operator/delay.ts#L52.

For example consider the following example:

Observable.from([1,2,3], Scheduler.async)
  .subscribe(val => console.log(val));

Observable.from(['a','b','c'], Scheduler.async)
  .subscribe(val => console.log(val));

Which schedules each emission into another JS callback:

1
"a"
2
"b"
3
"c"

See demo: https://jsbin./zalugev/3/edit?js,console

If you don't set any scheduler everything will be emitted immediately (synchronously):

Observable.from([1,2,3])
  .subscribe(val => console.log(val));

Observable.from(['a','b','c'])
  .subscribe(val => console.log(val));

Which prints the following:

1
2
3
"a"
"b"
"c"

See demo: https://jsbin./zalugev/4/edit?js,console

Regarding your question, you shouldn't rely on the 3rd party library to emit values immediately because you never know when this changes and your code will break.

An Observable is essentially just a wrapper for onSuccess(), onError() and onComplete() callbacks. If functions that are executed are synchronous an Observable will be too. This is core functionality of an Observable (the rest is just cleanup):

export class Observable {
  constructor(subscribe) {}
  subscribe(observerOrNext, error, plete) {} // callbacks
}
Observable.create = (subscribe) => {
    return new Observable(subscribe); // dot-chaining
}

Watch this video where André Staltz constructs observable from scratch.

Not sure if that could be the issue here, but some observables emit synchronously. This is the case of Observable.of for example I believe. If translateService is synchronous, you would then immediately get your subscription observer called and your translation value filled.

You can influence the timing of the emission by using schedulers, which is probably the less documented part of rxjs. Have a look at https://github./ReactiveX/rxjs/blob/master/MIGRATION.md, section Schedulers Renamed

Your translateString function returns immediately because of your return translation line fires before the observable pletes. Observables are async and thus your this.translateService.get(stringToTranslate) hasn't pleted before the return statement.

I would remove the return statement and just let the data value get assigned to translation when the observable pletes. If you are trying to chain functions together, I would look at flatMap to call another function on the response of this.translateService.get(stringToTranslate).

The subscribe behaves in a way like a callback in that it executes the observable and gives the response in a success/error/pleted fashion.

....subscribe(
    data => //success data,
    error => //error data,
    pleted => //observable pleted
);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论