我有一个组件,用户可以在其中 Select 要生成的报告类型.

Component.ts函数如下所示:

generateReport(reportType, projectReport) {
  this.showSpinner = true;
  if(reportType === 'project-weekly-report')
    this.router.navigate(['/weeklyReport', projectReport]).catch<any>(this.handleError.bind(this));
  else this.router.navigate(['/monthlyReport']).catch<any>(this.handleError.bind(this));
}

它转发到的这条路由有一个使用解析器来处理报表加载的组件.组件的ngOnInit()如下所示:

ngOnInit(): void {
   this.report = this.route.snapshot.data['projectWeeklyReport'].result;
}

解析器如下所示:

@Injectable()
export class ProjectWeeklyReportResolve implements Resolve<any> {

  constructor(private reportService: ReportService, private http: HttpClient) {}

  resolve(route: ActivatedRouteSnapshot) {
    return this.reportService.getProjectWeeklyReport(route.paramMap.get('projectName'));
  }
}

此解析器调用服务中的以下函数:

getProjectWeeklyReport(projectName) {
  var workerUrl = this.reportUrl + '/weeklyreport/projectname/' + projectName + '/job/';
  return this.http
    .get<any>(this.reportUrl + '/weeklyreport/projectname/' + projectName, this.getAuthOptions(true))
    .pipe(
      switchMap(workerId => this.pollFor(workerId, isWorkerCompleted, isWorkerFailed, 2000, workerUrl)),
      catchError(this.handleError)
    );
}

此方法访问服务器以通知它开始生成报告.由于生成报告需要一些时间,因此该作业(job)已被分派给工作人员作业(job).然后,我们轮询此工作人员作业(job),以判断报告是否已完成生成报告.

轮询函数如下所示:

type CustomPollOperator = (data: any, condComp: (d) => boolean, condFail: (d) => boolean, ms: number, url: string) => Observable<any>

const isWorkerCompleted = w => w.result;
const isWorkerFailed = w => w.failedReason;

//Convenience method for polling operation
pollFor: CustomPollOperator = (data, condComp, condFail, ms, url) => {
  let shouldPoll = true;

  return interval(ms)
    .pipe(
      tap(() => console.warn('polling', shouldPoll)),
      takeWhile(() => shouldPoll),
      switchMap(() => this.http.get<any>(url + data.id, this.getAuthOptions(true))),
      tap(res => {
        if(condComp(res)) {
          shouldPoll = false;
        }
        else if(condFail(res)) {
          shouldPoll = false;
          throw new Error('Polling worker job failed');              
        }
      }),
      catchError(this.handleError)
    )
}

在我将Angular 从9更新为14之前,当SwitchMap和CustomPollOperator完成其工作时,解析器将收到完成的报告.

但是,在更新Angular 版本之后,解析器不会等待轮询完成,而是在作业(job)的第一个请求开始后立即加载页面.

你知道是什么导致了这个问题吗?当不涉及解析器时,我在其他地方使用相同的代码,并且它的功能与以前一样.

首先要感谢大家!

推荐答案

pollFor将发出该行的第一个结果:

switchMap(() => this.http.get<any>(url + data.id, this.getAuthOptions(true))),

这将导致该路径被解析.

如果你想阻止这种情况的发生,你需要应用一个过滤器.我只会把tap换成filter,在轮询完成时返回true,否则返回false.这将仅在轮询完成后发出结果.

return interval(ms).pipe(
    tap(() => console.warn('polling', shouldPoll)),
    takeWhile(() => shouldPoll),
    switchMap(() =>
      this.http.get<any>(url + data.id, this.getAuthOptions(true))
    ),
    filter((res) => {
      if (condComp(res)) {
        shouldPoll = false;
        return true;
      } else if (condFail(res)) {
        shouldPoll = false;
        throw new Error('Polling worker job failed');
      }
      return false;
    }),
    catchError(this.handleError)
  );

我真的不确定为什么这个在Angular 9会有不同的表现,尽管我从来没有在那个版本中使用过解析器.您确定在解决问题之前需要多次轮询吗?请记住,interval不会立即排放.间隔定时也是初始延迟.

Angular相关问答推荐

Angular 17@在大小写时切换多个值

CDK虚拟滚动由于组件具有注入属性而在滚动时看到错误的值

角material 17 -如何从Style.scss中的主题中获取原色

按Angular 从组件的 bootstrap 选项卡中删除活动类

筛选器不会从文本输入触发更改事件

是否自动处理Angular /RxJS观测数据的取消订阅

Angular 16独立依赖注入问题

Angular 信号 - 使用 mutate() 与使用 forEach() react 性

无法创建新的 Ionic 项目

Angular Mat Select 显示键盘焦点和鼠标悬停焦点的问题

Angular 15 Ref 错误:初始化前无法访问组件 A

BehaviorSubject 在 Angular 中制作数据之间的时间表(或计时器)

Angular:组件的内容投影访问数据

使用 BehaviorSubject 从服务更新 Angular 组件

Angular:try 在点击次数后禁用按钮

如何在 Angular 4 中获取 HttpClient 状态码

如何处理解析器中的错误

从 angular2 模板调用静态函数

Angular CLI 输出 - 如何分析Bundle 文件

Angular 2 更改事件 - 模型更改