【发布时间】:2019-06-11 14:03:16
【问题描述】:
我遇到了一个奇怪的情况,当我订阅 observable 之前异步管道无法正常工作。资料来源:
组件视图:
<div *ngIf="loading$ | async" fxLayout="row" fxLayoutAlign="center">
<span class="spinner">Loading...</span>
</div>
<h1>{{data$ | async}}</h1>
组件:
@Component({
selector: './tm-fake',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './fake.component.html'
})
export class FakeComponent implements OnInit {
constructor(
private _fs: FakeService
) {}
loading$ = new BehaviorSubject<boolean>(false);
data$ = this._fs.data$.pipe(indicateUntilNULL(this.loading$));
ngOnInit(): void {
this._fs.requestData();
//this.data$.subscribe(e => {});
}
}
服务:
@Injectable()
export class FakeService {
requestData(): void {
timer(2000).pipe(map(e => "data")).subscribe(e => this._data.next(e));
}
private readonly _data = new BehaviorSubject<string>(null);
readonly data$ = this._data.asObservable();
}
操作员:
export function indicateUntilNULL<T>(indicator: BehaviorSubject<boolean>): (source: Observable<T>) => Observable<T> {
return source => source.pipe(
tap(e => indicator.next(!e))
);
}
我看到data 在 2 秒延迟后按预期显示,但在此延迟期间我没有看到微调器。但是,如果我取消注释 this.data$.subscribe(e => {}); 行,它就会开始正常工作。而且我找不到原因。有什么想法吗?
注意:loading$ 发出正确的值,即使此行被注释。
解决方案
非常感谢@theMayer 和他的有益建议。我只想添加article,这里有详细解释问题。根据这篇文章,最优雅的解决方案是delay(0) 运算符:
export function indicateUntilNULL<T>(indicator: BehaviorSubject<boolean>): (source: Observable<T>) => Observable<T> {
return source => source.pipe(
delay(0),
tap(e => indicator.next(!e))
);
}
【问题讨论】:
-
为什么用 Null 进行初始化?这不是它应该被使用的方式
-
您可以尝试仅打印
{{ loading$ | async }}吗?因为即使使用onPush,您所拥有的也应该可以工作。 -
@theMayer 因为页面加载后我没有数据。它应该从 API 请求。为了简单起见,我用计时器代替了它
-
@martin 相同-我用
<h1>{{loading$ | async}}</h1>替换了一个微调器,它在没有订阅的情况下一直显示为假,并且在订阅时按预期工作-首先它显示true,然后-延迟后@ 987654335@. -
布尔值在逻辑上只能是真或假。我建议用一个值来初始化它。