为啥 subscribe() 不起作用但模板中的异步可以?

Posted

技术标签:

【中文标题】为啥 subscribe() 不起作用但模板中的异步可以?【英文标题】:Why does subscribe() not working but aync in template does?为什么 subscribe() 不起作用但模板中的异步可以? 【发布时间】:2019-08-13 07:28:18 【问题描述】:

有一个套接字服务可以在应用程序之间发送和接收消息。我可以发送消息,也可以使用getMessages | async 在模板中接收这些消息。但是当我尝试在我的组件中用getMessages().subscribe(...) 替换getMessages | async 时,它不再起作用了。那么我做错了什么?

这是组件代码:

@Component(
    selector: 'showTemplate',
    template: `<ng-container #dynamicTemplate>
                    <div class="mx-auto m-5" 
                        [innerhtml]="content" 
                    ">
                </div>

                <!-- WORKS
                    <div *ngFor="let x of showContent() | async">
                         x | json --
                    </div>
                -->
            </ng-container>`,
    providers: [ SocketService ]
)
export class ShowTemplateComponent implements OnInit 
    @Input() data:any;

    constructor(
        private socketService: SocketService,
    ) 
    


    ngOnInit() 
        this.socketService.connect();

        // doesn't work
        this.socketService.getMessages().subscribe(response => 
            console.log("------", response)
        )
    

    /**
     *
     *
     */
    public showContent() 
        return this.socketService.getMessages();
    

服务如下所示:

import  Injectable                    from "@angular/core";
import  Observable, of, Subject       from 'rxjs';
import  WebSocketSubject              from 'rxjs/observable/dom/WebSocketSubject';

import  environment                   from '@app/../environments/environment';
import  Message                       from "../model/message";
import  Status                        from "../model/status";

@Injectable()
export class SocketService 
    public serverMessages = new Array<Message>();   
    private socket$: WebSocketSubject<Message>;
    private status: Status;
    private connected: Status;
    private decoderSettings;

    /**
     *
     */
    constructor(
        private authenticationService: AuthenticationService,
    ) 
        console.log("SOCKET SERVICE INIT")
        // get logged user
        this.decoderSettings = this.authenticationService.decoderSettings;

        this.connect();     
    

    public connect(): void 

        const CONTENT_SERVER_URL = 'wss://' + this.decoderSettings.ipAddress + ':9041';

        this.socket$ = new WebSocketSubject(
                        url: CONTENT_SERVER_URL,
                        openObserver: 
                            next: value => 
                                console.log("OPEN", value);
                                this.status = Status.CONNECTED;
                            
                        ,
                        closeObserver: 
                            next: value => 
                                console.log("CLOSEING", value);
                                this.status = Status.DISCONNECTING;
                            
                        
                    );

        this.socket$
            .subscribe(
                (message) => 
                    console.log('SEND', message);
                    this.serverMessages.push(message);
                ,
                (err) =>   
                    this.status = Status.ERROR;
                    console.error(err);
                ,
                () => 
                    console.warn('CLOSED!');
                    this.status = Status.DISCONNECTED;
                
            );
        

        public disconnect(): void 
            this.socket$.unsubscribe();
        

        public send(message: Message): void 
            console.log("send: ", message)
            this.socket$.next(message);
        

        public getMessages():Observable<any> 
            console.log("getMessages: ", this.serverMessages)
            return of(this.serverMessages);
        
    

我希望这只是一个简单的错误,但经过长时间的搜索后我真的找不到它。非常感谢您的帮助!

【问题讨论】:

定义“不再起作用” @JamieRees 很好,我希望在this.socketService.getMessages().subscribe(...) 中看到任何新收到的消息。但这里没有显示任何内容。模板中带有&lt;div *ngFor="let x of showContent() | async"&gt; 的代码向我显示任何新消息 订阅时,您是否从订阅中获取价值?例如subscribe(message =&gt; this.messages = message);? @JamieRees subscribe() 的内部部分只被调用一次。然后是向我显示一个空数组console.log(response)。所以答案是,是的。但它只显示一次,任何进一步的消息都会被忽略。 【参考方案1】:

public getMessages():Observable<any> 
            console.log("getMessages: ", this.serverMessages)
            return of(this.serverMessages);
        

您正在创建一个 Observable,它发出您传递给它的值 (this.serverMessages),然后完成。您应该创建一个 BehaviourSubject 而不是 serverMessages 数组。然后,您应该告诉 BehaviourSubject 发出一个新值,而不是推送到 Array。 https://www.learnrxjs.io/subjects/behaviorsubject.html

【讨论】:

我也试过BehaviourSubject,但它也不起作用【参考方案2】:

我相信它可以工作,因为在 html 中,每当重新渲染视图时,您都会重新订阅,触发对 getMessages() 的新调用,创建一个新的 Observable 以返回。

虽然在代码中您只订阅了一次,但我可能错了,但您返回 Observable 的模式似乎是错误的,因为仅向您的数组添加内容不会触发对先前返回的 Observable 的更新。

编辑:如果您在服务的 getMessages() 方法中设置断点,您会获得多少次命中?如果我是正确的,如果您专注于视图,那么您应该每秒获得几次点击。

【讨论】:

【参考方案3】:

不出所料-我的大脑被炸了。这解决了我的问题:

    public getMessages():Observable<any> 
        return this.socket$;
    

【讨论】:

以上是关于为啥 subscribe() 不起作用但模板中的异步可以?的主要内容,如果未能解决你的问题,请参考以下文章

为啥模板参数推导在 C++ 中不起作用?

为啥 WCF 休息服务(不是使用 WCF 休息服务模板创建的)不起作用?

在 service.subscribe 中组件的构造函数中的 Angular 更新不起作用

为啥(ngModel)不起作用?

为啥我在 Vue 中的移动标签效果不起作用?

为啥 Laravel 中的新路线不起作用?