如何从 angular 中的 Observable/http/async 调用返回响应?

IT技术 javascript angular asynchronous typescript observable
2020-12-16 23:08:55

我有一个服务,它返回一个 observable,它向我的服务器发出 http 请求并获取数据。我想使用这些数据,但我总是得到undefined. 有什么问题?

服务:

@Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}

成分:

@Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}

我检查了如何从异步调用返回响应?发帖但找不到解决办法

6个回答

原因:

原因undefined是您正在进行异步操作。这意味着完成该getEventList方法需要一些时间(主要取决于您的网络速度)。

所以让我们看看 http 调用。

this.es.getEventList()

在您实际发出(“触发”)您的 http 请求后,subscribe您将等待响应。在等待时,javascript 将执行此代码下方的行,如果遇到同步分配/操作,它将立即执行它们。

因此,在订阅getEventList()并等待响应后,

console.log(this.myEvents);

行将立即执行。并且它的值是undefined在响应从服务器到达之前(或者你首先初始化它的任何东西)。

它类似于:

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}


解决方案:

那么我们如何克服这个问题呢?我们将使用作为subscribe方法的回调函数因为当数据从服务器到达时,它会subscribe在响应中。

所以把代码改成:

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });

将打印响应......一段时间后。


你应该做什么:

除了记录它之外,您的回复可能还有很多事情要做;subscribe当数据到达时,您应该在回调中(在函数内部执行所有这些操作

另一件要提到的是,如果您来自Promise后台,则then回调对应于subscribeobservables。


你不应该做的事情:

您不应该尝试将异步操作更改为同步操作(您不能这样做)。我们有异步操作的原因之一是不要让用户等待操作完成,而他们可以在该时间段内做其他事情。假设您的一项异步操作需要 3 分钟才能完成,如果我们没有异步操作,界面将冻结 3 分钟。


推荐阅读:

这个答案的原始功劳是:如何从异步调用返回响应?

但是随着 angular2 的发布,我们被引入了 typescript 和 observables,所以这个答案有望涵盖使用 observables 处理异步请求的基础知识。

我的问题有点相似。但是这个答案也解决了这个问题。:-)
2021-02-24 23:08:55
当提问者在发布帖子的同一时间回答问题时.. 这是一个停下来写博客文章的好地方
2021-03-02 23:08:55
@JonasPraem 是的,但在 Stackoverflow 上分享知识并没有错。正如您所看到的投票数量,它确实帮助了这里的许多人,并且将继续这样做。
2021-03-03 23:08:55

在 angular/javascript 中进行 http 调用是异步操作。因此,当您进行 http 调用时,它将分配新线程来完成此调用,并在下一行与另一个线程开始执行。这就是为什么你得到未定义的value。所以进行以下更改以解决此问题

this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });

如果仅在模板中使用myEvents,则可以使用 asyncPipe。

这里以 asyncPipe 和 Angular4 HttpClient为例

并且(!)通过这个实现,不需要取消订阅订阅:medium.com/@sub.metu/...
2021-02-13 23:08:55
@SanJayFalcon 由于这是一个 http 请求,因此无需取消订阅。
2021-03-07 23:08:55

Observable 是惰性的,因此您必须订阅才能获取值。您在代码中正确订阅了它,但同时在“订阅”块之外记录了输出。这就是为什么它是“未定义的”。

ngOnInit() {
  this.es.getEventList()
    .subscribe((response) => {
        this.myEvents = response;
    });

  console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}

因此,如果您将其记录在 subscribe 块中,那么它将正确记录响应。

ngOnInit(){
  this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //Inside the subscribe block 'http response'
    });
}

这里的问题是,要初始化this.myEventssubscribe()它是一个异步块,而你正在做console.log()只是出于subscribe()块。所以console.log()this.myEvents初始化之前调用

请将您的 console.log() 代码也移动到 subscribe() 中,您就完成了。

ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents);
        });
  }