将多个顺序可观察量合并为一个可观察量

时间:2019-12-30 18:14:35

标签: javascript angular typescript rxjs

我需要将多个http调用的结果合并为一个Observable。调用必须按顺序进行,每个调用都必须等待上一个调用结束,并且直到运行时才知道http调用的数量。

我见过类似的问题,但是初始调用的数目一直是已知的,因此,几个嵌套和/或链接的管道操作可以轻松地解决这个问题。我将需要进行0到* API调用。

认为 concatMap()是必经之路,但我可能是错的。而且我不知道使它起作用的语法。

// Post all phones to API individually, but return updated results in single array.
savePhones(phones: Phone[]): Observable<Phone[]> {

    let updatedPhones: Phone[] = [];

    if (phones.length === 0) {
        return of<Phone[]>(updatedPhones);
    }

    // I need to do something like this, but for 1 to **many** phones. 
    // When each Observable completes, add to array.
    // Only after the prior Observable completes, start the next.
    // When the last one is done, return the Observable array. 
    return this.postPhone(contactId, phones[0])
        .pipe(
            map(response1 => {
                let p1 = new Phone();
                p1.loadFromJson(response1);
                updatedPhones.push(p1);
            }),
            concatMap(() => this.postPhone(contactId, phones[1])
                .pipe(map(response2 => {
                    let p2 = new Phone();
                    p2.loadFromJson(response2);
                    updatedPhones.push(p2);
                }))),
            concatMap(() => this.postPhone(contactId, phones[2])
                .pipe(map(response3 => {
                    let p3 = new Phone();
                    p3.loadFromJson(response3);
                    updatedPhones.push(p3);
                }))),
            map(() => {
                return updatedPhones;
            })
        );

}

private postPhone(
    contactId: string,
    phone: Phone): Observable<Phone> {

    let criteria = phone.toJson();
    let url = phone.isNew()
        ? `${apiUrl}/contacts/${contactId}/phones/add`
        : `${apiUrl}/contacts/${contactId}/phones/${phone.phoneId}/update`;

    return this.httpClient.post(url, criteria));
}

谢谢。

1 个答案:

答案 0 :(得分:0)

尝试forkJoin

savePhones(phones: Phone[]): Observable<Phone[]> {
    return phones.length === 0 ? of<Phone[]>([]) : forkJoin(phones.map(
      phone => this.postPhone(contactId, phone).pipe(
        map(response => new Phone().loadFromJson(response)),
      )
    ));
}