You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 9中用RxJS Observable实现延迟显示骨架屏

优雅实现:仅当请求超500ms时显示骨架屏(Angular 9 + RxJS)

你的思路完全正确!核心就是延迟触发loading状态,避免快速请求时的骨架屏闪烁,用RxJS的Observable可以非常优雅地实现这个逻辑,而且完全贴合Angular的响应式编程风格。

实现方案思路

我们可以通过两个Observable的组合来实现:

  • 一个是你的REST请求流,负责获取数据
  • 另一个是500ms的定时器流,负责延迟触发loading状态

利用RxJS的race操作符,让这两个流“竞争”:如果请求在500ms内完成,就直接跳过loading;如果500ms到了请求还没结束,就触发loading显示骨架屏。同时用async管道自动管理订阅,避免手动操作带来的内存泄漏问题。

具体代码实现

组件逻辑(.ts文件)

import { Component, OnInit } from '@angular/core';
import { Observable, timer, of, race } from 'rxjs';
import { map, shareReplay, catchError, concatWith, startWith } from 'rxjs/operators';
import { YourDataService } from './your-data.service'; // 替换成你的数据服务

@Component({
  selector: 'app-item-list',
  templateUrl: './item-list.component.html'
})
export class ItemListComponent implements OnInit {
  items$: Observable<any[]>;
  loading$: Observable<boolean>;

  constructor(private dataService: YourDataService) { }

  ngOnInit(): void {
    // 定义请求流,用shareReplay确保只发一次请求
    const dataRequest$ = this.dataService.fetchItems().pipe(
      shareReplay(1),
      // 处理请求错误,确保loading能正常关闭
      catchError((error) => {
        console.error('数据加载失败:', error);
        return of([]);
      })
    );

    // 构建loading状态流:
    // 1. 500ms后发出true(准备显示骨架屏)
    // 2. 如果请求先完成,就发出false(跳过骨架屏)
    // 3. 初始状态为false,请求完成后最终状态也为false
    this.loading$ = race(
      timer(500).pipe(map(() => true)),
      dataRequest$.pipe(map(() => false))
    ).pipe(
      startWith(false),
      concatWith(of(false))
    );

    // 赋值数据流供模板使用
    this.items$ = dataRequest$;
  }
}

模板代码(.html文件)

<div *ngIf="!(loading$ | async); else skeleton">
  <span *ngFor="let item of items$ | async">{{item}}</span>
</div>
<ng-template #skeleton>
  <my-skeleton></my-skeleton>
</ng-template>

关键细节说明

  • race操作符:它会订阅所有传入的Observable,第一个发出值的Observable会被采纳,其他Observable会被自动取消订阅。完美实现“谁快听谁的”逻辑。
  • shareReplay(1):确保dataRequest$被多个订阅者(loading$和items$)共享,不会触发多次REST请求。
  • async管道:自动管理Observable的订阅和取消,避免内存泄漏,同时让模板代码更简洁。
  • 错误处理:通过catchError确保即使请求失败,loading状态也能正确关闭,不会一直显示骨架屏。

这种方案完全满足你的需求,既解决了骨架屏闪烁的问题,又符合Angular的最佳实践,代码简洁易维护。

内容的提问来源于stack exchange,提问作者Slash90ITA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 08:32:53