如何在Angular 5中进行同步调用?

18

所以,我尝试解决这个问题。但由于我在 Angular 5 中的知识不足,所以我无法做到。这是我的服务:

GetCurrentUserData(): Observable<ResponseData> {
    return this.http.get<ResponseData>(ApplicationURLS.GetCurrentUserInformation)
        .map(response => {
            return response;
        });
    //.catch(error => this.handleError(error));
}

这是我的组件:

public GetCurrentUserInformation(): any {

        return this.loginService.GetCurrentUserData().subscribe(data => { return data; });
    }

我在尝试访问数据:

ngAfterViewInit() {
        debugger;                
        this.responseData = this.GetCurrentUserInformation();
        if (this.responseData.code != responseCodes.success) {
            this.googleInit();
        }

    }

当我检查this.responseData时,它总是返回这个,但我想要数据:

enter image description here

我只想发起同步调用,以便可以立即获取数据。

我也尝试在服务中使用do(),但它返回“do()不是一个函数”。


3
我认为在这里使用async/await可能是最佳选择。 - Muhammed Albarmavi
@malbarmawi 是的。 - Just code
7个回答

34

可以通过使用async/await来简化这个过程。

public GetCurrentUserInformation(): Promise<any>{
    return this.loginService.GetCurrentUserData().toPromise()
}

ngAfterViewInit

async ngAfterViewInit() {    
        this.responseData = await this.GetCurrentUserInformation(); // ‍♂️ 
        if (this.responseData.code != responseCodes.success) {
            this.googleInit();
        }
    }

@Emanuele Bellini:这个“this.responseData.code != responseCodes.success”的意思是什么?它是否会在等待发送任何代码字段时触发? - SwapnilM
@SwapnilM 不是的:await 允许获取结果而不是 Promise,就像它是同步调用一样。所以我猜测它是由 GetCurrentUserData() 返回的字段,类型为 any - Emanuele Bellini

8

订阅GetCurrentUserData()时,http调用是异步的(每个浏览器API调用都是异步的,因为JavaScript引擎在单个线程中运行(请搜索浏览器事件循环获取更多信息,这不是一个Angular问题))

this.GetCurrentUserInformation().subscribe((data: ResponseData) => {
        if (this.responseData.code != responseCodes.success) {
            this.googleInit();
        }
});

没错,我刚刚意识到了这一点,并做出了相应的更改,现在它按预期工作。 - Just code
1
你忘记设置 this.responseData = data - Muhammed Albarmavi

5
为了确保异步调用在处理响应之前执行,您可以使用来自ReactiveX的Observable.forkJoin()。
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';

Observable.forkJoin(
    this.http.get('/links.json').map((response:Response) => response.json()),
    this.http.get('/bookmarks.json').map((response:Response) => response.json())
).subscribe(
    data => {
      this.links = data[0]
      this.bookmarks = data[1]
    },
    error => console.error(error)
);

当所有 HTTP 请求成功完成时,subscribe() 函数的 onNext 处理程序将被执行。


5

异步函数不能同步调用,因为它们是异步的。

subscribe 通常不应该在预期被链接的方法中执行。即使应该执行,也应该从方法中返回 observable 而不是 subscription (subscription 可以额外保存以在销毁时取消订阅)。

GetCurrentUserInformation 方法是冗余的,因为它只是一个服务调用的包装器。代码可以重构为:

ngAfterViewInit() {
    this.loginService.GetCurrentUserData().subscribe(data => {
        this.responseData = data;
        if (this.responseData.code != responseCodes.success) {
            this.googleInit();
        }
    });
}

是的,+1。我本来应该先完成这个函数的。但是,正如你所指出的,G.viteli帮助了我,现在我能够理解它了。 - Just code
同意,但你可以使用async/await,这样它看起来就像异步的。 - Muhammed Albarmavi
这不会是同步调用,而且你不能决定该 公共 方法是否应该被重构为 ngAfterViewInit,因为它对外界暴露了一些含义(希望如此 ;))。 - Youp Bernoulli

1
使用subscribe的complete方法是使调用同步的最佳方式。

source$.subscribe({ next: doSomething, error: doSomethingElse, complete: lol }).

如果我们订阅了某些内容,并且想在完成此订阅后执行一些操作,则可以将代码编写在complete中。
详细阅读请参考: https://rxjs.dev/deprecations/subscribe-arguments

谢谢。非常好的答案。拯救了我的一天。 - Jafar Amini

1
使用以下同步的http请求:

使用同步的http请求如下

var request = new XMLHttpRequest();
request.open('GET', "https://domain/api", false);  
request.send(null);
const response = JSON.parse(request.responseText); 

无法使用HttpClient来利用DI,因此应在必要时绝对使用。

0

没有直接的方法可以进行同步调用,但是您可以执行以下过程(此代码编写在Angular 7中)。

import { Component, OnInit } from '@angular/core';
import {HttpClient} from '@angular/common/http';

export class SampleComponent implements OnInit {
  Request1result:Object;
  Request2result:Object;

  constructor(private http:HttpClient) { }

   ngOnInit() 
   {
    this.http.get("URL1").subscribe((res)=>{
      this.Request1result=res;
      this.after1(); // execution will move to next request only when first is done.
    });
   }
  after1()
  {
    this.http.get("URL2").subscribe((res)=>{
      this.Request2result=res;
      this.after2(); // execution will move to the rest of the code only when both the requests are done.
    });
  }
  after2()
    {
    // rest of the code.
    console.log(this.Request1result);
    console.log(this.Request2result);

    }

}


更好的做法是使用flatMap()链接Observables。 - Michal.S

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