Angular 2 从 RxJs 订阅返回数据

Posted

技术标签:

【中文标题】Angular 2 从 RxJs 订阅返回数据【英文标题】:Angular 2 return data from RxJs subscribe 【发布时间】:2016-07-20 11:03:26 【问题描述】:

我有一个具有身份验证功能的服务 -

authenticate(username: string, password: string) 
        let ret;
        let packet = JSON.stringify(
            username: username,
            password: password
        );

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');

        this.http.post('http://localhost:5000/api/authenticate/', packet, 
            headers: headers
        )
        .map(res => res.json())
        .subscribe(
            data =>  
                // put return data into ret
                ret = data.token;
            ,
            err => console.log(err),
            () => 
                // this works!
                console.log(ret);
            
        );

        // get's returned before I put data into it
        return ret;
    

所以如果我调用验证函数console.log(authenticate('a', 'b'));,它会记录undefined,因为ret 变量在订阅函数可以将数据放入其中之前返回。如何从身份验证函数返回 http 响应数据?我以前从来没有用 RxJS 做过任何反应式编程,这就是 angular 2 似乎正在使用的东西。

PS。有没有像 go channels 或 core.async 这样像样的 javascript 的 CSP 解决方案?

【问题讨论】:

这并不是 async 或 RxJs 的真正工作方式;您不会从异步函数返回数据。 我想了这么多,因为在我返回 ret 变量后 subscribe 被执行。关于在处理 RxJS 时如何返回数据的任何想法? 你可以创建另一个方法,比如 this.authenticateFinished(ret) console.log(ret); // 和其他任何东西 然后从 data => 调用它 好吧,subscribe 在您返回之前执行,但它是异步的。我不知道 AngJS 的“方式”是什么,但你要么需要回调,要么需要观察者,或者 RxJS 使用的任何事件流机制。 【参考方案1】:

您需要直接返回与您的请求对应的可观察对象:

authenticate(username: string, password: string) 
  let ret;
  let packet = JSON.stringify(
    username: username,
    password: password
  );

  let headers = new Headers();
  headers.append('Content-Type', 'application/json');

  return this.http.post('http://localhost:5000/api/authenticate/', packet, 
    headers: headers
  )
  .map(res => res.json());

authenticate 方法的调用者必须订阅它才能接收结果:

this.service.authenticate('username', 'password').subscribe(
  (result) => 
    console.log('Result received');
    console.log(result);
  
);

【讨论】:

谢谢。但是,我希望所有逻辑都进入服务而不是组件内部。我想通了。【参考方案2】:

我使用 Observables 和 Observers 来构建我的解决方案。由于@Injectable 创建了一个单例类,我在其中声明了一个 Observable,然后将其暴露给我的组件。当我将任何数据放入其中时,所有订阅者都会收到该事件的通知。警告:如果你将它与 zone.js 0.5 一起使用,它将无法工作。适用于 0.6。

import Observable from 'rxjs/Observable';
import Observer from 'rxjs/Observer';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';


@Injectable()
export class AuthService 
    // expose to component
    notification$: Observable<Notification>;
    private observer: Observer<Notification>;

    ....

    constructor(private http: Http) 
        this.notification$ = new Observable(observer => this.observer = observer).share();
    

    authenticate(username, password) 
        let packet = JSON.stringify(
            username: username,
            password: password
        );

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');

        this.http.post(`$this.baseUri/authenticate/`, packet, 
            headers: headers
        )
        .map(res => res.json())
        .subscribe(
            data => 
                if (data.success && data.token) 
                    this.saveJwt(data.token);
                 else 
                    this.deleteJwt();
                
                // put data into observavle 
                this.observer.next(
                    message: data.message,
                    type: data.success
                );
            ,
            err => 
                // put data into observavle  
                this.observer.next(
                    message: 'Error connecting to server',
                    type: false
                )
            ,
            () => 
        );
    



export class AuthComponent implements OnInit 
    observable: Observable<Notification>;

    ...

    ngOnInit() 
        // subscribe to the observable
        this.observable = this.authService.notification$;
        this.observable.subscribe(
            data => 
                ...
            
        )
    

【讨论】:

什么是“私人观察者:观察者”中的通知?我可以传递给观察者什么? 只需将 替换为

以上是关于Angular 2 从 RxJs 订阅返回数据的主要内容,如果未能解决你的问题,请参考以下文章

Angular中利用rxjs库的Subject多播解决在第一次订阅时进行初始化操作(如第一次订阅时从服务器获取数据)

Angular 7 RxJs - HTTP 调用未在 ForkJoin 中完成

Angular / RxJs对一个observable的多个订阅

Angular 6 - 无法订阅从服务返回的数据

关于rxjs subject订阅分发实现Angular的全局数据管理与同步更新

Angular/RxJS 6:如何防止重复的 HTTP 请求?