Angular 和 rxJS。流永远不会完成

RG

我在 angular 应用程序中有一个菜单,这个菜单控制我的 Web 应用程序中选定的客户端。

因为它是:

  • 我的菜单是一个组件,它通过服务共享选定的客户端。
  • 选定的客户端作为 Observable 共享。
  • 可观察对象永远不会完成。单击菜单时,它只会发出新的选定客户端。
  • 这是一个重播主题。每个新订阅者检索最后发出的客户端。

这似乎是一个不错的设计,但是在基于客户端创建新的 observables 时我遇到了一些问题(从未完成 observables)。AFAIK 这是由于第一个 observable 永远不会完成并且此属性将传播。

//Command
export interface Command {
    productName: string;
    qty: number;
}

//The service
@Injectable()
export class ClientService {
private _client: ReplaySubject<Client> = new ReplaySubject(1);

    setClient(client: Client) { // The menu component calls setClient on a user click
        this._client.next(client);
    }
    getClient(): Observable<Client> { // getClient is heavilly called in child component to observe client selection events.
        return this._client.asObservable();
    }
}


getCommands(): Observable<Command> { //Used in a template with async pipe

    //In a child component
    const commandsObs = this.clientService.getClient()
    //.take(1) //I am forced to use take(1) to get getCommands() observer to complete
    .flatMap(c => {
        return Observable.merge(getCommandsPromise1(c), getCommandsPromise2(c));
    })
    .reduce((acc, next) => Object.assign({}, acc, next))
    .map(next => {
        return finishMakingCommand(next));
    })
    .catch(err => /* Some error management code*/)
}

getCommandsPromise1(client: Client): Promise<any> {
    //REST call returning a promise
    return Promise.resolve({ 'command1': { 'productName': 'toy', qty: 1 } });
}
getCommandsPromise2(client: Client): Promise<any> {
    //REST call returning a promise
    return Promise.resolve({ 'command2': { 'productName': 'another toy', qty: 1 } });
}

finishMakingCommand(commands: any): Command[] {
    // Flattens 'command1' and 'command2' to a list of commands
    return [{'productName': 'toy', qty: 1}, {'productName': 'another toy', qty: 2}];
}

我想知道更有经验的开发人员是否认为永无止境的 observable 是一个好的设计,以及有哪些替代方案可以避免永无止境的 observables。

理查德·马森

正如我上面提到的,将 observables 视为铺设管道。唯一出现问题的时候是水不断涌来(就像Observable.interval(1000)水源一样——它会一直滴答作响)。在这种情况下,如果您手动订阅 observable,您还需要取消订阅。

但是,正如您所说,您使用的是异步管道,而 Angular 负责取消订阅。

通过单击菜单,一键将发送一个值。可观察对象永远不会完成(即永远不会收到完成的事件)是很常见的,这不是必需的。

Completed 事件对于聚合操作符通常很有用,例如toArray()让他们知道整个值集。

我建议只使用

const commandsObs = this.clientService.getClient();

并在模板中(示例)

<div>{{ commandObs | async }}</div>

忘记 flatMap,除非它打算做一些花哨的事情 - 让我知道。

编辑 - 对新示例代码的建议更改

您可以尝试在 flatmap 内移动 reduce 和 map,因为它们旨在处理内部 observable (Observable.merge) 的结果。

const commandsObs = this.clientService.getClient()
  .flatMap(c => {
    return Observable.merge(getCommandsPromise1(c), getCommandsPromise2(c))
      .reduce((acc, next) => Object.assign({}, acc, next))
      .map(next => finishMakingCommand(next) )
  });

尝试的替代版本,

const commandsObs = this.clientService.getClient()
  .map(c => Observable.forkJoin(getCommandsPromise1(c), getCommandsPromise2(c) );

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章