Angular让subscribe等待响应

7

我正在尝试订阅一个Observable并从响应中分配一些数据,但是我的代码不等待响应。基本上,console.log(this.newIds)首先运行,并且始终为空,因为订阅不等待后端的响应。我该如何强制代码等待响应?

 this.repository.getById(Ids).subscribe((response) => {
      console.log(response);
      this.newIds = response.map((id) => {
        return id;
      });
    });
    console.log(this.newIds);
5个回答

6
如果您将代码放在订阅回调函数中,它将在收到后端响应后执行。所有您在此函数之外编写的代码都将直接执行。
     this.repository.getById(Ids).subscribe((response) => {
          //Code will execute when back-end will respond
          console.log(response);
          this.newIds = response.map((id) => {
            return id;
          });
          console.log(this.newIds);
        });
//Code will execute immediately

参见:https://angular.io/guide/observables#creating-observables

谢谢!我还有一个问题。实际上我想使用this.newIds变量,而不仅仅是将其记录下来,所以我仍然需要等待响应的到来,否则该变量仍将为空(我不想在subscribe里面使用它)。我应该使用Promise而不是Observable吗? - anyway07
1
不,我觉得 Promise 在 Angular 中已经过时了。我猜你需要设置一个 ngrx 存储来管理在多个组件中使用的数据。如果你没有时间设置这个,可能只需使用 @Input。如果您可以提出一个新问题以帮助其他用户,并对第一个问题进行验证,那就是另一个问题了。谢谢 :)。 - Pterrat
但是对于这种特殊情况,他仍然可以使用 .toPromise() 将可观察对象转换为 Promise。 - Mohamad Al Asmar
1
@MohamadAlAsmar 是的,你说得对。这是可能的。我认为仅使用可观察对象而不是可观察对象+承诺等更容易保持一个干净的应用程序。 - Pterrat

3
这是正常的行为,因为你的console.log(this.newIds);在订阅之外,你只需要将它移到.subscribe()方法内部即可:
 this.repository.getById(Ids).subscribe((response) => {
          console.log(response);
          this.newIds = response.map((id) => {
            return id;
          });
          console.log(this.newIds);
    });

如果您想在订阅之外并在观察者结果之后立即使用this.newIds,可以使用RxJs的 .toPromise() 将其用作Promise,并将方法更改为async:

async callerFn(){

    const response = await this.repository.getById(Ids).toPromise();
  
    this.newIds = response.map((id) => {
        return id;
    });
    console.log(this.newIds);
    // use your property here

 }

谢谢!还有一个问题。实际上我想使用this.newIds变量,而不仅仅是记录它,所以我仍然需要等待响应到来,否则变量仍将为空(我不想在subscribe内部使用它)。我应该使用Promise而不是Observable吗? - anyway07
更新了答案。 - Mohamad Al Asmar

2

是的,因为Javascript是逐行解释执行的,所以它不会等待其他进程完成。这就是为什么最后一个控制台返回undefined的原因。与此同时,如果你在订阅者内部使用控制台,则可以获得正确的日志,因为订阅者将等待响应并将其绑定到this.newIds上。

 this.repository.getById(Ids).subscribe((response) => {
      console.log(response);
      this.newIds = response.map((id) => {
        return id;
      });
     console.log(this.newIds);
    });

我在这里附上一篇关于Observable订阅的好文章

https://betterprogramming.pub/observables-vs-promises-which-one-should-you-use-c19aef53c680

此外,如果您想在订阅范围之外使用newIds访问,请使用promise和async await。以下是一个示例

 async getAsyncData() {
    this.asyncResult = await this.httpClient.get<Employee>(this.url).toPromise();
    console.log('No issues, I will wait until promise is resolved..');
  }

谢谢!还有一个问题。其实我想使用this.newIds变量,而不仅仅是将其记录在日志中,所以我仍然需要等待响应的到来,否则该变量仍将为空(我不想在订阅内使用它)。我应该使用Promise代替Observable吗? - anyway07
是的,您可以在async await中使用promise,我将更新答案并提供一个示例。 - Jijo Alexander

1
您可以这样做...
您的组件文件如下所示:
newIds: Observable<any> = of(this.id).pipe(
concatMap((id) =>
  this.getId(id).pipe(map((data) => data.map((rowId) => rowId.id)))
)
);
getId(id: any) {
  return of([{ id: 1 }, { id: 2 }, { id: 3 }]);
}

你的 HTML 文件如下所示,使用 async 管道进行订阅。在这里,你可以使用 concatMap 管道 RxJS 运算符来按顺序调用可观察对象,然后将值分配给你的 newId 变量。

<pre>
  {{ newIds | async }}
</pre>

请查看这个实时链接的演示 Stackblitz链接


0
我会采用不同的方法:如果您需要重新映射值,可以使用map运算符:

 this.repository.getById(Ids)
  .pipe(map(response) => response.map(id => id))
  .subscribe((id) => {
      console.log(response);
      this.newIds = id;
  });

其实,我不明白为什么你需要映射一个已经存在的值,但我认为这是一个清晰的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接