【问题标题】:Angular 4 Service method returns always undefined instead ObservableAngular 4 Service 方法总是返回 undefined 而不是 Observable
【发布时间】:2018-01-21 11:02:09
【问题描述】:

我编写了一个 Angular 服务,它通过 socket.io 连接到我的后端。我在_getStripes() 方法中正确获取了服务器数据,并使用from() 将它们转换为Observable,并使用最近创建的observable 设置类变量_LEDs

公共方法getStripes()在另一个组件中被调用和订阅,每次都返回undefined

led.service.ts:

import {Injectable} from '@angular/core';
import * as io from 'socket.io-client';
import {LED} from './led';
import {Observable} from 'rxjs/Observable';
import {from} from 'rxjs/observable/from';

@Injectable()
export class LedService {
  private _io;
  private _LEDs: Observable<LED>;

  constructor() {
    this._io = io('http://localhost:80');
    // Subscribe getStripes Event
    this._io.on('getStripes', this._getStripes);

    // Initial Request Stripes from Server
    this._io.emit('getStripes');
  }

  /**
   * Server Response
   * @param {LED[]} data
   * @private
   */
  private _getStripes(data: LED[]) {
    console.log('Got Stripes: ', data); // works
    this._LEDs = from(data);
  }

  /**
   * Get the current connected LEDStripes
   * @returns {Observable<LED>}
   */
  public getStripes(): Observable<LED> {
    // request latest Stripes
    this._io.emit('getStripes');
    return this._LEDs; // always undefined
  }

  public setStripeColor(name: string, color: string) {
    this._io.emit('setStripeColor', name, color);
  }

}

【问题讨论】:

  • 这可能是竞争条件吗?我猜想return 是在处理emit 之前发生的。就像一个测试,如果你睡在getStripes 中的emitreturn 之间,让其他一切有机会“安顿下来”,会发生什么?

标签: angular typescript socket.io rxjs


【解决方案1】:

您需要将订阅与发出分开。

Subscription 设置管道接收传入数据,但 emit 发送数据。看起来是 request/response 的风格,因为 event 和 emit params 是同一个字符串,但是无论如何两者之间都有时间延迟,所以需要提前建立 pipeline。

尝试为this._LEDS 使用主题

服务中

import {Injectable} from '@angular/core';
...
import {Subject} from 'rxjs/Subject';

@Injectable()
export class LedService {
  private _io;
  private _LEDs = new Subject<LED>();
  public LEDs = this._LEDs.asObservable();  // Subscribe to this

  constructor() {
    ...
    // Subscribe getStripes Event
    this._io.on('getStripes', this._getStripes.bind(this) );
    ...
  }

  /**
   * Server Response
   * @param {LED[]} data
   * @private
   */
  private _getStripes(data: LED[]) {
    data.forEach(led => this._LEDs.next(led));
    // OR send the whole array as a single emit if it suits your application better
    //    this._LEDs.next(data);
    // in which case the declaration above would be
    //    private _LEDs = new Subject<LED[]>();
  }

  /**
   * Get the current connected LEDStripes
   * @returns void
   */
  public getStripes(): void {
    // request latest Stripes
    this._io.emit('getStripes');
  }

在组件中

ngOnInit() {
  // subscribe to the LEDs
  this.sub = this.ledService.LEDS.subscribe(leds => {
    // do something with data
  }) 
  // or use the subscription directly in the template
  // with <div> {{ (ledService.LEDS | async) }} </div>
}

getFresh() {
  this.ledService.getStripes();
}

【讨论】:

  • 在 forEach 循环中出现此错误:Cannot read property 'next' of undefined 我已经检查过是否遗漏了什么。
  • .nextthis._LEDs 上,所以要么这行和声明行之间存在大小写差异,要么你没有在声明行上初始化它(: 而不是=)?
  • 注意,我在上面的评论中打错了(已修复)
  • 确实,很奇怪。可能需要一点时间。
  • 我会说这是this 的问题。您能否请console.log('this', this) 在上面的行中查看它具有哪些属性?我怀疑它会在socket.io-client 中显示事件处理程序的属性,而不是您的服务的属性。
猜你喜欢
  • 2019-05-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 2021-06-04
  • 2017-03-18
  • 2016-01-16
  • 1970-01-01
相关资源
最近更新 更多