简体   繁体   English

如何从内部有 Observable 订阅的 function 返回值?

[英]How to return value from function which has Observable subscription inside?

I dont know how to extract value from Observable to be returned by function in which Observable is present.我不知道如何从存在 Observable 的 function 返回的 Observable 中提取值。 I need just a value from it to be returned, nothing else.我只需要从中返回一个值,没有别的。

Current version which works有效的当前版本

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            console.log(data)
        }
    )
}
getValueFromObservable()

I need this to work, function to return value, and then:我需要这个工作,function 返回值,然后:

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

What am I doing wrong here?我在这里做错了什么?

EDIT: updated code in order to reflect changes made to the way pipes work in more recent versions of RXJS.编辑:更新代码以反映在 RXJS 的最新版本中对管道工作方式所做的更改。 All operators (take in my example) are now wrapped into the pipe() operator.所有运算符(以我的示例为例)现在都包含在 pipe() 运算符中。

I realize that this Question was quite a while ago and you surely have a proper solution by now, but for anyone looking for this I would suggest solving it with a Promise to keep the async pattern.我意识到这个问题是很久以前的事了,现在你肯定有一个合适的解决方案,但对于任何寻找这个问题的人,我建议用 Promise 来解决它以保持异步模式。

A more verbose version would be creating a new Promise:更详细的版本是创建一个新的 Promise:

function getValueFromObservable() {
    return new Promise(resolve=>{
        this.store.pipe(
           take(1) //useful if you need the data once and don't want to manually cancel the subscription again
         )
         .subscribe(
            (data:any) => {
                console.log(data);
                resolve(data);
         })
    })
}

On the receiving end you will then have "wait" for the promise to resolve with something like this:在接收端,您将“等待”承诺以如下方式解决:

getValueFromObservable()
   .then((data:any)=>{
   //... continue with anything depending on "data" after the Promise has resolved
})

A slimmer solution would be using RxJS' .toPromise() instead:更精简的解决方案是使用 RxJS 的 .toPromise() 代替:

function getValueFromObservable() {
    return this.store.pipe(take(1))
       .toPromise()   
}

The receiving side stays the same as above of course.接收方当然和上面一样。

This is not exactly correct idea of using Observable这不是使用Observable完全正确的想法

In the component you have to declare class member which will hold an object (something you are going to use in your component)在组件中,您必须声明将持有对象的类成员(您将在组件中使用的东西)

export class MyComponent {
  name: string = "";
}

Then a Service will be returning you an Observable :然后Service将返回一个Observable

getValueFromObservable():Observable<string> {
    return this.store.map(res => res.json());
}

Component should prepare itself to be able to retrieve a value from it: Component应该准备好能够从中检索值:

OnInit(){
  this.yourServiceName.getValueFromObservable()
    .subscribe(res => this.name = res.name)
}

You have to assign a value from an Observable to a variable:您必须将Observable的值分配给变量:

And your template will be consuming variable name :并且您的模板将消耗变量name

<div> {{ name }} </div>

Another way of using Observable is through async pipe http://briantroncone.com/?p=623另一种使用Observable是通过async管道http://briantroncone.com/?p=623

Note : If it's not what you are asking, please update your question with more details注意:如果这不是您要问的问题,请使用更多详细信息更新您的问题

If you want to pre-subscribe to the same Observable which will be returned, just use如果您想预订阅将返回的同一个 Observable,只需使用

.do(): .do():

function getValueFromObservable() {
    return this.store.do(
        (data:any) => {
            console.log("Line 1: " +data);
        }
    );
}

getValueFromObservable().subscribe(
        (data:any) => {
            console.log("Line 2: " +data)
        }
    );

The problem is that data is captured inside the observable and I can just console log it.问题是数据是在 observable 中捕获的,我可以通过控制台记录它。 I want to return that value and console.log or whatever from different file by calling the function in which it resides.我想通过调用它所在的函数来返回该值和 console.log 或来自不同文件的任何内容。

Looks like you are looking for a "current value" getter inside an observable, when it emits and after an emission.看起来您正在 observable 中寻找“当前值”getter,当它发射时和发射后。

Subject and Observable doesn't have such a thing. SubjectObservable没有这样的东西。 When a value is emitted, it is passed to its subscribers and the Observable is done with it.当一个值被发出时,它被传递给它的订阅者并且Observable用它完成。

You may use BehaviorSubject which stores the last emitted value and emits it immediately to new subscribers.您可以使用BehaviorSubject来存储最后发出的值并立即将其发送给新订阅者。

It also has a getValue() method to get the current value;它还有一个getValue()方法来获取当前值;

Further Reading:进一步阅读:

RxJS BehaviorSubject RxJS 行为主题

How to get current value of RxJS Subject or Observable? 如何获取 RxJS Subject 或 Observable 的当前值?

Observable values can be retrieved from any locations.可以从任何位置检索可观察值。 The source sequence is first pushed onto a special observer that is able to emit elsewhere.源序列首先被推送到一个能够在别处发射的特殊观察者 This is achieved with the Subject class from the Reactive Extensions (RxJS).这是通过 Reactive Extensions (RxJS) 中的Subject 类实现的。

var subject = new Rx.AsyncSubject();  // store-last-value method

Store value onto the observer .将值存储到观察者上

subject.next(value); // store value
subject.complete(); // publish only when sequence is completed

To retrieve the value from elsewhere, subscribe to the observer like so:要从其他地方检索值,请像这样订阅观察者:

subject.subscribe({
  next: (response) => {
      //do stuff. The property name "response" references the value
  }
});

Subjects are both Observables and Observers. Subjects 既是 Observables 又是 Observers。 There are other Subject types such as BehaviourSubject and ReplaySubject for other usage scenarios.对于其他使用场景,还有其他主题类型,例如 BehaviourSubject 和 ReplaySubject。

Don't forget to import RxJS.不要忘记导入 RxJS。

var Rx = require('rxjs');

While the previous answers may work in a fashion, I think that using BehaviorSubject is the correct way if you want to continue using observables.虽然以前的答案可能以某种方式起作用,但我认为如果您想继续使用 observable,使用 BehaviorSubject 是正确的方法。

Example:示例:

    this.store.subscribe(
        (data:any) => {
            myService.myBehaviorSubject.next(data)
        }
    )

In the Service:在服务中:

let myBehaviorSubject = new BehaviorSubjet(value);

In component.ts:在 component.ts 中:

this.myService.myBehaviorSubject.subscribe(data => this.myData = data)

I hope this helps!我希望这会有所帮助!

For example this is my html template:例如,这是我的 html 模板:

<select class="custom-select d-block w-100" id="genre" name="genre"
                  [(ngModel)]="film.genre"
                  #genreInput="ngModel"
                  required>
            <option value="">Choose...</option>
            <option *ngFor="let genre of genres;" [value]="genre.value">{{genre.name}}</option>
          </select>

This is the field that binded with template from my Component:这是与我的组件中的模板绑定的字段:

  // Genres of films like action or drama that will populate dropdown list.
  genres: Genre[];

I fetch genres of films from server dynamically.我从服务器动态获取电影类型。 In order do communicate with server I have created FilmService为了与服务器通信,我创建了FilmService

This is the method which communicate server:这是与服务器通信的方法:

 fetchGenres(): Observable<Genre[]> {
    return this.client.get(WebUtils.RESOURCE_HOST_API + 'film' + '/genre') as Observable<Genre[]>;
  }

Why this method returns Observable<Genre[]> not something like Genre[] ?为什么这个方法返回Observable<Genre[]>而不是类似于Genre[]东西?

JavaScript is async and it does not wait for a method to return value after an expensive process. JavaScript 是async ,它不会等待一个方法在一个昂贵的过程之后返回值。 With expensive I mean a process that take a time to return value.昂贵的意思是一个需要时间来返回值的过程。 Like fetching data from server.就像从服务器获取数据一样。 So you have to return reference of Observable and subscribe it.所以你必须返回 Observable 的引用并订阅它。

For example in my Component :例如在我的组件中:

ngOnInit() {
    this.filmService.fetchGenres().subscribe(
      val => this.genres = val
    );
  }

In the single-threaded,asynchronous,promise-oriented,reactive-trending world of javascript async/await is the imperative-style programmer's best friend:在单线程、异步、面向承诺、响应式趋势的 javascript async/await世界中, async/await是命令式程序员最好的朋友:

(async()=>{

    const store = of("someValue");
    function getValueFromObservable () {
        return store.toPromise();
    }
    console.log(await getValueFromObservable())

})();

And in case store is a sequence of multiple values:如果store是多个值的序列:

  const aiFrom = require('ix/asynciterable').from;
  (async function() {

     const store = from(["someValue","someOtherValue"]);
     function getValuesFromObservable () {
        return aiFrom(store);
     }
     for await (let num of getValuesFromObservable()) {
       console.log(num);
     }
  })();
function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

In above case console.log runs before the promise is resolved so no value is displayed, change it to following在上面的例子中,console.log 在 promise 被解决之前运行,所以没有显示任何值,将其更改为以下

function getValueFromObservable() {
    return this.store
}

getValueFromObservable()
 .subscribe((data: any) => {
    // do something here with data
    console.log(data);
});

other solution is when you need data inside getValueFromObservable to return the observable using of operator and subscribe to the function.其他解决方案是当您需要 getValueFromObservable 中的数据以使用运算符返回可观察对象并订阅该函数时。

 function getValueFromObservable() {
        return this.store.subscribe((data: any) => {
            // do something with data here
            console.log(data);
            //return again observable.
            return of(data);
       })
    }

    getValueFromObservable()
     .subscribe((data: any) => {
        // do something here with data
        console.log(data);
    });

The decent way would be to return the observable from a function and subscribe to it wherever required, because observables are lazy, they will start emitting values only when they are subscribed.体面的方法是从函数返回 observable 并在任何需要的地方订阅它,因为 observables 是惰性的,它们只有在订阅时才会开始发出值。

Here I have one more interesting event driven solution, which I initially used to play around with.在这里,我有一个更有趣的事件驱动解决方案,我最初使用它。 Following example does this by using " events " module of nodejs.以下示例通过使用 nodejs 的“ events ”模块来完成此操作。 You can use it with other frameworks where similar module exists ( Note : Syntax and style might change depending on module used).您可以将它与存在类似模块的其他框架一起使用注意:语法和样式可能会根据所使用的模块而变化)。

var from =require("rxjs").from;
var map = require("rxjs/operators").map;
var EventEmitter = require("events");

function process(event) {
    from([1,2,3]).pipe(
        map(val => `The number is:: ${val}`)
    ).subscribe((data) => {
       event.emit("Event1", data); //emit value received in subscribe to the "Event1" listener
    });
}

function main() {
   class Emitter extends EventEmitter{};
    var event = new Emitter(); //creating an event
    event.on("Event1", (data)=>{ //listening to the event of name "Event1" and callback to log returned result
        console.log(data); //here log, print, play with the data you receive
    });
    process(event); //pass the event to the function which returns observable.
}

main(); //invoke main function

It is just an example to showcase an idea where we can pass data from different places by method of emitting and listening.这只是一个例子,展示了我们可以通过发送和监听的方法从不同地方传递数据的想法。 This is also known as event-driven code.这也称为事件驱动代码。

Returning an observable from a function.从 function 返回一个 observable。

rxjsFunction.ts rxjs函数.ts

import { Observable } from 'rxjs'

export function getValueFromObservable() {

    return new Observable( (obs) => {
        obs.next(5);
    })
}

main.ts主.ts

import { getValueFromObservable } from "./rxjsFunction";

getValueFromObservable().subscribe((value) => {
    next: console.log(value);
});

I wanted to check if the data was stored on the client, or if I had to get it from the server via API call.我想检查数据是否存储在客户端上,或者我是否必须通过 API 调用从服务器获取数据。 Then returning a new observer and subscribing to this did the trick.然后返回一个新的观察者并订阅它就可以了。 The first time the data is fetched from the server and after is return the this.allUsers, since I set this data after the API was called and data was returned.第一次从服务器获取数据,之后返回 this.allUsers,因为我在调用 API 并返回数据后设置了此数据。

    private _allUsers: EnconUser[] = undefined;
    get allUsers(): EnconUser[]
    {
      return this._allUsers;
    }
    set allUsers(value: EnconUser[])
    {
      this.storage.store('allUsers', value);
      this._allUsers = value;
    }

    public getAllUsers() : Observable<EnconUser[]>
    {
      if (this.allUsers == undefined)
      {
        return new Observable((obs) => {this.httpClient.get<EnconUser[]>(`http://api/getallusers`).subscribe(data=>{this.allUsers=data; obs.next(data); })});
      }
      else
      {
       return new Observable((obs) => {
        obs.next(this.allUsers);
        });
      }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM