将带有异步管道的可观察对象传递给输入会导致调用 http 方法的无限循环并且不返回任何值

Passing an observable with async pipe to an input causes an infinite loop of calling http method and no value is returned

我有一个 table,其中有一列需要来自 HTTP 请求的每条记录的值,因此我使用了一种 returns 可观察值的方法,如下所示:

getItem(obj): Observable<string> {
        return this.http.get('/someServiceurl').pipe(
          map(res => {
            var x = res.element
            return x;
          });
      }

在table行如下(输入为字符串类型):

    <td>
        <component [input]="(getItem(obj) | async)">
        </component>
    </td>

尽管值是从 HTTP 调用返回的,但即使没有将值传递给组件输入,它也会进入无限的 HTTP 调用。
那么是什么原因造成的,还有另一种方法可以在循环中为 table 中的每个元素异步调用 HTTP。
提前致谢。

这是整个 table 结构:

<p-table [value]="mainList" 
            [totalRecords]="Count" [paginator]="true" [showCurrentPageReport]="true"
            currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries" [rows]="5">
    <ng-template pTemplate="header">
        <tr>
            <th>..........</th>
            <th>..........</th>
            <th>..........</th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-obj>
        <tr>
            <td>{{obj.date}}</td>
            <td>{{obj.status}}</td>
            <td>
                <component [input]="(getItem(obj) | async)">
                </component>
            </td>
        </tr>
    </ng-template>
</p-table>   

那个

<component [input]="(getItem(obj) | async)"></component>

看起来是罪魁祸首(让我猜猜,更改检测策略:默认?)。在每个变更检测周期中,表达式 getItem(obj) 都会被评估,http.get 被调用,请求发出,我猜这会触发变更,这会触发变更检测,我们再来一次。

一个可能的解决方案:来自

http.get('/someServiceurl').pipe(map(res => res.element))

制作烟斗:

@Pipe({name: 'getItem'})
export class GetItemPipe implements PipeTransform {
  constructor(private http: HttpClient) {}

  transform(value: string): Observable<SomeInterface> {
    return this.http.get(value).pipe(map(res => res.element));
  }
}

并在模板中:

<component [input]="obj | getItem | async"></component>

是的,这导致了无限变化检测循环。在每个变更检测周期中模板 运行 中的函数,这会导致构造一个新的可观察对象,这会导致异步管道变为 运行,然后异步管道的输出会导致变更检测周期。冲洗,重复。

pipe 方法的工作原理是通过确保仅在其输入(在本例中为obj)发生变化时才构建可观察对象来打破循环。如果您需要经常以相同的方式构建相同的可观察对象,这可能是更合适的课程,但如果您只是在这里这样做,可能会有点繁重。

另一种方法是在 table 中的项目上设置 observable。类似的东西。

// this is just a guess / example. i don't know how your mainList is actually built
this.mainList = this.service.fetchList().map(i => {
  i.item$ = this.getItem(i);
  return i;
})

然后在模板中:

<component [input]="obj.item$ | async"></component>

这同样确保列表中每个项目的可观察对象仅在构建列表本身时构建。

另一种选择是只处理子组件中的订阅,但可能出于其他原因不想这样做。