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

eko*_*eko 92 javascript asynchronous observable typescript angular

我有一个服务,它返回一个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)
  }
}
Run Code Online (Sandbox Code Playgroud)

零件:

@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!
  }
}
Run Code Online (Sandbox Code Playgroud)

eko*_*eko 100

原因:

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

所以让我们来看看http调用.

this.es.getEventList()
Run Code Online (Sandbox Code Playgroud)

实际制作("开火")后,您的http请求subscribe等待响应.在等待时,javascript将执行此代码下面的行,如果遇到同步赋值/操作,它将立即执行它们.

所以在订阅getEventList()并等待响应后,

console.log(this.myEvents);

线将立即执行.并且它的值是undefined在响应从服务器到达之前(或者在您首先初始化它的任何内容).

它类似于:

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

    console.log(this.myEvents); //This prints undefined!
}
Run Code Online (Sandbox Code Playgroud)


解:

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

所以将代码更改为:

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

将在一段时间后打印回复.


你应该做什么:

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

另外要提到的是,如果你来自Promise背景,则then回调对应于subscribeobservable.


你不该做的事:

您不应该尝试将异步操作更改为同步操作(不是您可以).我们进行异步操作的原因之一是不让用户等待操作完成,而他们可以在该时间段内执行其他操作.假设您的一个异步操作需要3分钟才能完成,如果我们没有异步操作,则接口将冻结3分钟.


推荐阅读:

这个答案的最初归功于:如何从异步调用中返回响应?

但是对于angular2版本,我们被引入了typescript和observables,所以这个答案希望涵盖处理带有observables的异步请求的基础知识.

  • 当提问者在帖子的同一时间回答问题时..这是一个停下来写博客文章的好地方 (2认同)
  • @JonasPraem是的,但在Stackoverflow上分享知识并没有错.当你看到投票数量时,它确实帮助了很多人,并且会继续这样做. (2认同)
  • 我的问题有点相似。但这个答案也解决了这个问题。:-) (2认同)

小智 9

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

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


Kli*_* Ru 6

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

这里以 asyncPipe 和 Angular4 HttpClient为例