【问题标题】:Angular 2 why aren't my 4 api calls waiting for the previous call to finish before executing?Angular 2 为什么我的 4 个 api 调用在执行前没有等待上一个调用完成?
【发布时间】:2018-02-17 10:55:48
【问题描述】:

我有一个form/component,它必须进行 4 次单独的 API 调用才能进行“保存”。确实,这些交易中只有一个需要等待其他 3 个,但为了安全起见,我还是想将所有 4 个都链接起来。

我是这样设置的:

save() {
    this.save1(saveObject1)
        .subscribe(response => {
            if (response === 0) {
                this.processErrorResult('save1');
            }

            this.save2(saveObject2)
                .subscribe(response2 => {
                    if (response2 === 0) {
                        this.processErrorResult('save1');
                    }

                    this.save3(saveObject3)
                        .subscribe(response3 => {
                            if (response3 === 0) {
                                this.processErrorResult('save1');
                            }

                            if (this.noErrorsInFirst3Saves()) {
                                this.save4(saveObject4)
                                    .subscribe(response4 => {
                                        if (response4 === 0) {
                                            this.processErrorResult('save1');
                                        }

                                        if (!this.hasErrors()) {
                                            this.router.navigate(['confirmation']);
                                        }
                                    });
                            }
                        });
                });
        });
}

private save1(saveObject: any): Observable<int> {
    this.api.save1(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save2(saveObject: any): Observable<int> {
    this.api.save2(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save3(saveObject: any): Observable<int> {
    this.api.save3(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

private save4(saveObject: any): Observable<int> {
    this.api.save4(saveObject)
        .subscribe(successful => {
            return Observable.of(1);
        }, failed => {
            return Observable.of(0);
        });
}

在每个 save{number} 函数中,我都有日志消息,因此我确切地知道这些函数的执行顺序(以及响应返回)。

当我点击保存时,它[几乎] 立即重定向到我的确认页面,然后我可以坐在那里在 chrome 开发工具中观看我的控制台窗口,并看到 API 调用的响应开始进入。

为什么这个设置不接受这些交易的显式链接?我知道在Angular 1 中,使用promise.then(response =&gt; {}); 很容易做到这一点。

我能想到的唯一不同的是,对于每个 API 调用,无论是 get/post/put/delete,它总是在网络面板中显示 2 个调用铬开发工具。第一次调用将RequestMethod 设置为Options,而随后的调用将对应的get/post/put/delete 设置为相应的RequestMethod

我不记得在我最近处理的任何应用程序中看到过这些(重复调用),(也许我只是从来没有关注过)所以也许这只是 API 调用的标准操作过程.

这里有什么想法吗?

编辑:回应哈利在下面的建议答案

我正在尝试实施您的答案,但对如何实施仍然有些困惑,请仔细查看我的设置:

private save1(saveObject: any): Observable<number> {
    if (saveObject.hasChanges()) {
        return this.api.save1(saveObject)
            .map(successful => {
                return this.parseSaveResponse(successful, saveObject, true); // true indicates a successful API response
            })
            .catch(failed => {
                return this.parseSaveResponse(successful, saveObject, false); // false indicates a successful API response
            });
    } else {
        return Observable.of(-1); // no changes necessary, return immediately
    }
}

private parseSaveResponse(response: any, saveObject: any, transactionSuccessful: boolean) {
    this.logService.logTransaction({transactionType}, saveObject, response, transactionSuccessful);

    if (!transactionSuccessful) {
        // add to error list object to be displayed on the form
        return 0;
    }

    return 1;
}

当它到达这一点时,它在.catch({}); 行上给我一个错误说:

类型参数 '(error: any) => 0 | 1' 不可分配给 '(err: any, catched: Observable) => 类型的参数 可观察输入'。键入'0 | 1' 不可分配给类型 '可观察输入'。 类型“0”不可分配给类型“ObservableInput”。)

【问题讨论】:

  • 查看 rxjs 中的 switchmap 转换运算符以链接您的调用。它可以将 Observable 作为输入,您可以使用它来调用您的其他 api。如果您想等待,可以查看 Observable.forkJoin 方法

标签: angular typescript angular-promise typescript2.0 angular-observable


【解决方案1】:

您的代码可能存在很多问题。首先,您的 save1/save2/save3 方法应该只返回您可以订阅的 API 中的 observable。

其次,您使用的是 Typescript 中不存在的 int 类型。使用数字

private save1(saveObject: any): Observable<number> {
  return this.api.save1(saveObject);
}
// or
private save1(saveObject: any): Observable<number> {
  return this.api.save1(saveObject).map(response => 1).catch(response => 0)
}

如果你想修改发射的项目,你可以添加 map 操作符,将发射的项目映射到其他东西。

最后,您应该避免从 observable 中订阅 observable。您可以使用 flatMap 运算符将 observables 链接在一起。这会将 Observable 发射的项目转换为 Observable,然后将这些项目的发射扁平化为单个 Observable。

save() {
  this.save1(saveObject1)
    .flatMap(response1 => this.save2(saveObject2))
    .flatMap(response2 => {
      if (response2 === 0) {
        // handle error
      }
      return this.save3(saveObject3);
    })
    .flatMap(() => this.save4(saveObject4))
    .subscribe(response4 => {
      // do redirect
    });
  }

http://reactivex.io/documentation/operators/flatmap.html

【讨论】:

  • 对不起,他们已经返回 Observable,这只是一个伪代码编写,忘记了我在打字稿世界而不是 C#。我会通读您的其余回复...
  • 我相信我已经成功了....一旦我通过更多测试确认,我会更新我的问题以获得工作版本,我会奖励你的答案。谢谢[我认为]...
【解决方案2】:

我认为你需要“返回”你的 observables。例如:

改变这个:

this.api.save1(saveObject)

收件人:

return this.api.save1(saveObject)

【讨论】:

  • 即使每个this.api.save1() 调用都有一个.subscribe,并且他们正在执行return Observable.of({number});
  • @ganders 是的。你需要两个回报
  • 只要我在你所说的地方添加返回,vscode 就会在整个块下抛出红色错误行:type subscription is not assignable to type Observable&lt;number&gt;
  • 返回 1 而不是 Observable.of(1)?从这里不确定
  • 试过了,没有改错。如果我从这一行中删除“: Observable&lt;int&gt; {private save1(saveObject: any): Observable&lt;int&gt; {,那么它会清除那里的错误,但随后会在保存函数中显示错误Property 'subscribe' does not exist on type 'Subscription | Observable&lt;number&gt;'
猜你喜欢
  • 1970-01-01
  • 2020-08-13
  • 2019-10-31
  • 2019-05-09
  • 2014-05-30
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
相关资源
最近更新 更多