Angular 4 Service方法始终返回undefined而非Observable问题求助
问题分析与解决方案
首先,你的代码里有两个核心问题导致getStripes()返回undefined:
1. this上下文丢失
当你把this._getStripes作为回调传给socket.io的on方法时,这个函数的this指向已经不再是LedService实例了——它会变成socket对象或者全局上下文。所以你在_getStripes里给this._LEDs赋值,其实根本没修改到类里的那个_LEDs属性,类实例的_LEDs始终是初始的undefined。
2. 异步数据流处理不当
就算this指向修复了,getStripes()里调用emit后立刻返回_LEDs的逻辑也有问题:socket的响应是异步的,你返回的时候服务器的数据可能还没传回来,这时候拿到的依然是旧值或者undefined。而且from(data)是一次性的Observable,每次新数据过来时,旧的Observable不会自动更新,订阅者也收不到最新数据。
修复方案
我们可以用RxJS的BehaviorSubject来管理数据流,同时修复this的绑定问题,具体步骤如下:
第一步:替换_LEDs为BehaviorSubject
BehaviorSubject会保存当前最新的数据状态,新订阅的组件能立刻拿到当前值,后续有新数据时也会自动推送。
第二步:修复this指向
把回调改成箭头函数,或者在构造函数里绑定this,确保_getStripes里的this指向服务实例。
第三步:调整getStripes的逻辑
让getStripes只负责触发服务器请求,组件通过订阅我们暴露的Observable来获取数据,而不是直接返回值。
修改后的完整代码:
import {Injectable} from '@angular/core'; import * as io from 'socket.io-client'; import {LED} from './led'; import {BehaviorSubject, Observable} from 'rxjs'; @Injectable() export class LedService { private _io; // 用BehaviorSubject保存LED数组,初始值设为空数组 private _LEDsSubject = new BehaviorSubject<LED[]>([]); // 对外暴露只读的Observable,防止外部直接修改数据 public LEDs$: Observable<LED[]> = this._LEDsSubject.asObservable(); constructor() { this._io = io('http://localhost:80'); // 用箭头函数确保this指向服务实例 this._io.on('getStripes', (data: LED[]) => this._handleStripesData(data)); // 初始请求灯带数据 this._io.emit('getStripes'); } private _handleStripesData(data: LED[]) { console.log('获取到灯带数据: ', data); // 更新Subject的值,所有订阅者都会收到新数据 this._LEDsSubject.next(data); } /** * 主动请求最新灯带数据 */ public refreshStripes(): void { this._io.emit('getStripes'); } public setStripeColor(name: string, color: string) { this._io.emit('setStripeColor', name, color); } }
组件中如何使用
在需要获取LED数据的组件里,直接订阅LEDs$即可:
import {Component, OnInit} from '@angular/core'; import {LedService} from './led.service'; import {LED} from './led'; @Component({ selector: 'app-led-list', template: ` <div *ngFor="let led of LEDs"> {{ led.name }} - {{ led.color }} </div> ` }) export class LedListComponent implements OnInit { LEDs: LED[] = []; constructor(private ledService: LedService) {} ngOnInit() { // 订阅实时数据 this.ledService.LEDs$.subscribe(leds => { this.LEDs = leds; }); // 如果需要主动刷新,调用这个方法 // this.ledService.refreshStripes(); } }
内容的提问来源于stack exchange,提问作者Joba
相关产品推荐
相关产品推荐

