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

多帖子评论提交:并发调用单API时如何显示带百分比的加载状态?

解决方案:用RxJS实现带进度追踪的批量评论提交

针对你的需求,我们可以通过RxJS的from+mergeMap+scan组合替代forkJoin,实现实时进度追踪、单个请求状态记录的批量提交。

实现步骤

1. 定义进度状态结构

先定义接口维护批量提交的进度和结果:

interface BatchProgress {
  total: number; // 总请求数
  completed: number; // 已完成请求数
  percentage: number; // 完成百分比
  successes: Array<{ postId: number; response: any }>; // 成功请求列表
  failures: Array<{ postId: number; error: any }>; // 失败请求列表
}

2. 封装批量提交函数

基于单个评论保存API,封装带进度追踪的批量提交逻辑:

import { from, Observable, of } from 'rxjs';
import { catchError, map, mergeMap, scan } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

// 帖子类型定义
interface Post {
  userId: number;
  postId: number;
  title: string;
  body: string;
  pictures: string[];
  date: string;
  lastModifiedDate: string;
}

export class CommentService {
  constructor(private http: HttpClient) {}

  // 单个评论保存API调用
  private saveSingleComment(postId: number, comment: string): Observable<any> {
    return this.http.post(`http://localhost:4200/post/${postId}`, { comment });
  }

  // 批量提交评论,接收包含帖子和对应评论的数组
  submitBatchComments(postsWithComments: Array<{ post: Post; comment: string }>): Observable<BatchProgress> {
    const totalRequests = postsWithComments.length;
    // 初始进度状态
    const initialProgress: BatchProgress = {
      total: totalRequests,
      completed: 0,
      percentage: 0,
      successes: [],
      failures: []
    };

    return from(postsWithComments).pipe(
      // 并发发起请求,第二个参数控制最大并发数(避免请求过载)
      mergeMap(item => 
        this.saveSingleComment(item.post.postId, item.comment).pipe(
          // 成功时包装结果,带上postId
          map(response => ({ type: 'success' as const, postId: item.post.postId, response })),
          // 捕获单个请求错误,返回失败结果(不中断整个批量流)
          catchError(error => of({ type: 'failure' as const, postId: item.post.postId, error }))
        ),
        3 // 示例:同时最多发起3个并发请求
      ),
      // 累计进度和结果
      scan((progress, result) => {
        const newCompleted = progress.completed + 1;
        const updatedSuccesses = [...progress.successes];
        const updatedFailures = [...progress.failures];

        if (result.type === 'success') {
          updatedSuccesses.push({ postId: result.postId, response: result.response });
        } else {
          updatedFailures.push({ postId: result.postId, error: result.error });
        }

        return {
          ...progress,
          completed: newCompleted,
          percentage: Math.round((newCompleted / totalRequests) * 100),
          successes: updatedSuccesses,
          failures: updatedFailures
        };
      }, initialProgress)
    );
  }
}

3. 组件中使用并更新UI

在组件里订阅Observable,实时更新加载状态、进度条和结果展示:

import { Component } from '@angular/core';
import { CommentService } from './comment.service';

@Component({
  selector: 'app-comment-submit',
  template: `
    <div *ngIf="progress">
      <div>提交进度:{{ progress.percentage }}%</div>
      <progress [value]="progress.percentage" max="100"></progress>
      
      <h3>成功提交</h3>
      <ul>
        <li *ngFor="let item of progress.successes">帖子ID {{ item.postId }}:提交成功</li>
      </ul>
      
      <h3>提交失败</h3>
      <ul>
        <li *ngFor="let item of progress.failures">帖子ID {{ item.postId }}:{{ item.error.message }}</li>
      </ul>
    </div>
    <button (click)="startBatchSubmit()">批量提交</button>
  `
})
export class CommentSubmitComponent {
  progress: BatchProgress | null = null;
  // 假设这里是用户输入了评论的帖子列表
  postsWithComments = [
    {
      post: {
        userId: 1,
        postId: 1,
        title: "Hello World",
        body: "post body will contain large text",
        pictures: ["1.jpg", "2.jpg"],
        date: "01/01/1970",
        lastModifiedDate: "01/02/1970"
      },
      comment: "这是帖子1的评论"
    },
    // 更多带评论的帖子...
  ];

  constructor(private commentService: CommentService) {}

  startBatchSubmit() {
    this.commentService.submitBatchComments(this.postsWithComments).subscribe(progress => {
      this.progress = progress;
      // 所有请求完成时的额外处理
      if (progress.completed === progress.total) {
        console.log("批量提交全部完成");
      }
    });
  }
}

核心逻辑说明

  • from(postsWithComments):将帖子数组转换为Observable序列,逐个发出带评论的帖子对象
  • mergeMap:对每个帖子发起API请求,通过catchError确保单个请求失败不中断整个流程;第二个参数控制并发数,避免服务器/浏览器过载
  • scan:实时累计请求结果,计算完成百分比,维护成功/失败列表,每次发出最新进度供UI更新
  • 对比forkJoin:无需等待所有请求完成即可反馈进度,单个失败不影响其他请求执行

可选调整

  • 若需串行提交(逐个执行请求),将mergeMap替换为concatMap即可,无需设置并发数
  • 可通过bufferCount运算符调整进度更新粒度,比如每完成N个请求更新一次UI

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:40:06