【问题标题】:How to make a synchronous call in angular 5?如何在角度 5 中进行同步调用?
【发布时间】:2018-05-16 06:54:27
【问题描述】:

所以,我试图解决这个问题。但是,不知何故我无法这样做,可能是因为缺乏角度 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 它总是返回这个而不是我想要数据:

我只想进行同步调用,以便立即获取数据。

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

【问题讨论】:

  • 我认为 async/await 可能是这里最好的情况????
  • @malbarmawi 是的

标签: angular typescript service angular-services angular-components


【解决方案1】:

这可以通过使用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 否:await 允许获取结果而不是 promise,就像它是一个同步调用一样。所以我猜是GetCurrentUserData()返回的字段,类型为any
【解决方案2】:

订阅GetCurrentUserData() http 调用是异步的(每个浏览器 api 调用都是异步的,因为 javascript 引擎在单个线程中运行(谷歌浏览器事件循环更多,这不是角度问题))

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

【讨论】:

  • 没错,我刚刚意识到这一点并进行了相应的更改,现在它正在按预期工作。
  • 你忘记设置this.responseData = data??
【解决方案3】:

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

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

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

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

【讨论】:

  • 是的,+1 我本来打算先完成这个功能。但是,是的,正如您指出的那样,G.viteli 帮助我,我现在能够理解它。
  • ? 同意,但你可以使用 async/await 会看起来像异步
  • 这不会是一个同步调用,也不是你决定应该将 public 方法重构为 ngAfterViewInit 的,因为它暴露给外部世界是有意义的(希望;))
【解决方案4】:

为了确保在处理响应之前执行异步调用,您可以使用来自 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)
);

subscribe() 函数的 onNext 处理程序将在所有 HTTP 请求成功完成后执行。

【讨论】:

    【解决方案5】:

    没有直接的方式进行同步调用,但是您可以执行以下过程(此代码是用 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
    【解决方案6】:

    如下使用同步 http请求

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

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

    【讨论】:

      【解决方案7】:

      使调用同步的最好方法是使用完整的订阅方法。

      source$.subscribe({ next: doSomething, error: doSomethingElse, 完成:大声笑})。

      如果我们订阅了一些东西,并且想要在完成这个订阅后做一些操作,那么我们可以完整地编写代码。

      详细阅读 https://rxjs.dev/deprecations/subscribe-arguments

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-23
        • 2021-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多