为啥数组的 Observable 和订阅者不起作用?

Posted

技术标签:

【中文标题】为啥数组的 Observable 和订阅者不起作用?【英文标题】:Why is the Observable and subscriber for an array not working?为什么数组的 Observable 和订阅者不起作用? 【发布时间】:2017-11-18 06:16:35 【问题描述】:

我正在尝试编写一个简单的错误处理服务。它可以接收错误并将它们添加到数组中,但由于某种原因,它不起作用。

errorhandling.service

@Injectable()
export class ErrorHandlingService 
    private errors: Array<ErrorMessage>;

    constructor() 
        this.errors = new Array<ErrorMessage>();
    

    getErrors(): Observable<Array<ErrorMessage>>
        return Observable.of(this.errors);
    

    handleError(error: Response, errorText: string) 
        let errorMessage = this.createErrorMessage(error);
        errorMessage.displayText = errorText;
        this.errors.push(errorMessage);
    

    private createErrorMessage(error: Response): ErrorMessage 
        let errorMessage: ErrorMessage = new ErrorMessage();
        errorMessage.errorType = error.type;
        errorMessage.statusCode = error.status;
        return errorMessage;
    


export class ErrorMessage 
    statusCode: number;
    displayText: string;
    errorType: ResponseType;

app.component.ts

export class AppComponent implements OnInit
    errorMessage: Message[] = [];
    constructor(private authService: AuthService, private renderer: Renderer, private errorhandlingService: ErrorHandlingService) 
        localStorage.removeItem(AppConstants.authenticationLocalStorageKey);
    

    ngOnInit(): void 
        this.errorhandlingService.getErrors().subscribe(errorMessages =>
            let errorMessage: ErrorMessage = errorMessages.pop();
            console.log(errorMessage);
            this.errorMessage = errorMessage ? [ severity: 'error', summary: '', detail: errorMessage.displayText ] : [];
        );
    

    onDeactivate() 
        //scroll to top of page after routing
        this.renderer.setElementProperty(document.body, "scrollTop", 0);
    

app.component.html

<div class="row">
        <div class="col-md-1"></div>
        <div class="col-md-10 well center-text">
            <p-messages [value]="errorMessage"></p-messages>
            <router-outlet (deactivate)="onDeactivate()"></router-outlet>
        </div>
        <div class="col-md-1"></div>
    </div>

下面的代码在另一个触发错误处理服务方法的组件中。

businessArea.component.ts

this.businessAreaService.getBusinessAreaById(id)
                    .subscribe(businessArea => 
                        this.model = businessArea;
                    ,
                    error => this.errorHandlingService.handleError(error, 'Could not load Business Area'));

编辑:我尝试了很多类似 Observable 的东西,但效果不佳。我不确定主题是什么以及如何使用它,但似乎 Observable 在我的场景中是有意义的。任何有用的链接也会有所帮助吗?我可以断点,我可以看到它命中了方法,然后它将错误推送到数组中,但永远不会调用 app.component 上的订阅。

预期行为: 当在错误情况下调用this.businessAreaService.getBusinessAreaById 时,它会调用errorHandlingService.handleError,后者通过调用方法this.errorHandlingService.handleError 将错误记录在errorHandlingService 的数组中。现在我在 app.component 中有一个订阅者,当错误添加到数组时应该调用它,以便我可以在 div 中显示错误。

什么不起作用: 在错误处理服务中将元素/错误添加到数组时,不会调用 app.component.ts 上的订阅者。不应该在数组触发订阅者中添加元素吗?只有在第一次调用 ngOnit 时才会调用它。在任何后续错误之后,不会调用订阅者。虽然我可以看到错误被推送到数组中。

【问题讨论】:

能否请您详细说明哪些功能不起作用以及您希望它做什么? @Raven 我已经编辑了我的问题,我不确定我还能写什么来更好地解释。你认为我的编辑有意义吗? 是的,一切正常。当我运行应用程序时,我在 console.log 中未定义,因为没有错误,但在后续调用中,它不会记录任何内容。第二次及以上时间不调用类似的订阅者 谢谢,编辑确实把事情弄清楚了。我敢肯定,您正在以错误的方式创建可观察对象以使其侦听更改。让我查一下 我很确定,我犯了一些根本性的错误。我已经阅读了很多文档,他们都建议 Observable.of 或 Observable.from...但似乎在第一次 Observable 后不会为订阅者触发。 【参考方案1】:

您可以使用Subject 来实现它,如下所示更新您的服务类中的代码,您无需修改​​除服务类之外的任何其他内容

import  Subject  from 'rxjs';

@Injectable()
export class ErrorHandlingService 
    private errors: Array<ErrorMessage>;
    private broadcaster = new Subject<Array<ErrorMessage>>();

    constructor() 
        this.errors = new Array<ErrorMessage>();
    

    getErrors(): Subject<Array<ErrorMessage>>
        return this.broadcaster;
    

    handleError(error: Response, errorText: string) 
        let errorMessage = this.createErrorMessage(error);
        errorMessage.displayText = errorText;
        this.errors.push(errorMessage);
        // letting all subscribers know of the new change
        this.broadcaster.next(this.errors);
    

    private createErrorMessage(error: Response): ErrorMessage 
        let errorMessage: ErrorMessage = new ErrorMessage();
        errorMessage.errorType = error.type;
        errorMessage.statusCode = error.status;
        return errorMessage;
    


export class ErrorMessage 
    statusCode: number;
    displayText: string;
    errorType: ResponseType;

【讨论】:

肯定会试试,subject 和 observable 有什么区别?抱歉,我对这些概念不熟悉 啊..我刚刚从移动设备切换到桌面来发布这个答案。请务必使用正确的 import import Subject from '@reactivex/rxjs/es6/Subject.js' 以避免任何与 tree-shaking 相关的问题。 SubjectObservable 相似,因为Subject 允许您订阅它以收听更新,但是Subjects 不要t 提供 Observables 提供的那些运营商,您必须在 Subject 上手动调用 next 以将更改推送给订阅者 Subjectcreate 函数的简单实现。要添加到此答案,使用 Observable.of 的原始实现不包含任何在流中推送新值的逻辑。这里.next()用于将变量推入流中。 @Raven Observable 没有 next 方法

以上是关于为啥数组的 Observable 和订阅者不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

可观察,在 ngOnDestroy 中取消订阅不起作用

来自数组的 Observable 在 TypeScript 中不起作用

为啥 Azure 事件中心订阅者不起作用?

如何在 RxSwift 中取消订阅 Observable?

为啥订阅在 Angular 中没有 Observable 的情况下工作

没有 ngOnDestroy,角度取消订阅不起作用